DCL 4.0
Loading...
Searching...
No Matches
FileOutputStream.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#if __DCL_WINDOWS
4 #include <windows.h>
5#else
6 #include <errno.h>
7 #include <dcl/_stat.h>
8#endif
9
10#include <string.h> // memcpy
11#include <stdlib.h> // malloc, free
12
13#include <dcl/Object.h>
14#include <dcl/Thread.h> // Thread::sleep
16
17#if __DCL_HAVE_ALLOC_DEBUG
18#undef __DCL_ALLOC_LEVEL
19#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
20#endif
21
22#if __DCL_DEBUG
23#undef __THIS_FILE__
24static const char_t __THIS_FILE__[] = __T("dcl/FileOutputStream.cpp");
25#endif
26
27__DCL_BEGIN_NAMESPACE
28
30
31String FileOutputStream::toString() const
32{
33 StringBuilder r = className();
34 if (__file)
35 r += __T("(") + __file->toString() + __T(")");
36 else
37 r += __T(" closed");
38 return r;
39}
40
41FileOutputStream::FileOutputStream(const String& _path, bool _truncate)
43{
44 __file = NULL;
45 open(_path, _truncate);
46}
47
50{
51 __buf = NULL;
52 __bufSize = 0;
53#if __DCL_WINDOWS
54 switch (_pFile->fileType())
55 {
56 case File::REGULAR:
57 __bufSize = 4096;
58 break;
59 case File::PIPE:
60 {
61 DWORD dwOutBufferSize = 0;
62 if (GetNamedPipeInfo(_pFile->handle(), NULL, &dwOutBufferSize, NULL, NULL))
63 __bufSize = dwOutBufferSize;
64 }
65 break;
66 }
67#else
68 struct stat st;
69 if (fstat(_pFile->handle(), &st)) // = -1
70 throw new IOException(_pFile->path(), errno);
71 if (S_ISBLK(st.st_mode))
72 __bufSize = st.st_blksize;
73
74#endif
75 __dataSize = 0;
76}
77
78FileOutputStream::FileOutputStream(File& _file)
80{
81 init(&_file);
82 __file = &_file;
83 __closeDestroy = false;
84}
85
86FileOutputStream::FileOutputStream(File::HandleType _handle)
88{
89 File* pFile = new File(_handle, 0, false);
90 try {
91 init(pFile);
92 }
93 catch (Exception* e) {
94 delete pFile;
95 throw e;
96 }
97 __file = pFile;
98 __closeDestroy = true;
99}
100
101FileOutputStream::FileOutputStream(File* __destroy__ _pFile)
103{
104 __DCL_ASSERT(_pFile != NULL);
105 try {
106 init(_pFile);
107 }
108 catch (Exception* e) {
109 delete _pFile;
110 throw e;
111 }
112 __file = _pFile;
113 __closeDestroy = true;
114}
115
116void FileOutputStream::open(const String& _path, bool _truncate)
118{
119 if (__file)
120 close();
121
122 File* pFile = new File(_path, File::WRITEONLY | File::CREATE
123 | (_truncate ? File::TRUNCATE : File::APPEND));
124 try
125 {
126 init(pFile);
127 }
128 catch (Exception* e)
129 {
130 delete pFile;
131 throw e;
132 }
133 __file = pFile;
134 __closeDestroy = true;
135}
136
137FileOutputStream::~FileOutputStream()
138{
139 if (__file != NULL)
140 {
141 try
142 {
143 close();
144 }
145 catch (IOException* e)
146 {
147 __DCL_TRACE1(L"~FileOutputStream close error! %ls\n", e->toString().data());
148 e->destroy();
149 }
150 }
152}
153
154void FileOutputStream::close()
156{
158
159 Exception* e = NULL;
160 try
161 {
162 flush();
163 }
164 catch (Exception* cause)
165 {
166 e = cause;
167 }
168
169 if (__buf)
170 {
171 free(__buf);
172 __buf = NULL;
173 __bufSize = 0;
174 __dataSize = 0;
175 }
176
177 File* file = __file;
178 __file = NULL;
179 if (__closeDestroy)
180 {
181 try
182 {
183 file->close();
184 }
185 catch (Exception* cause)
186 {
187 if (!e)
188 e = cause;
189 else
190 cause->destroy();
191 }
192 file->destroy();
193 }
194 if (e)
195 throw e;
196}
197
198inline size_t __write(File* _file, const byte_t* _buf, size_t _nbytes)
199{
200 size_t written = 0;
201 while (_nbytes)
202 {
203 size_t n = _file->write(_buf + written, _nbytes);
204 if (n)
205 {
206 written += n;
207 _nbytes -= n;
208 }
209 else
210 {
211 // errno == EAGAIN
212 // retry after 10 milliseconds
213 Thread::sleep(10);
214 }
215 }
216 return written;
217}
218
219void FileOutputStream::flush()
221{
223
224 if (__dataSize)
225 {
227 __dataSize = 0;
228 }
229}
230
231OutputStream& FileOutputStream::write(const void* _buf, size_t _nbytes)
233{
234 __DCL_ASSERT_HANDLE(__file != NULL);
235 __DCL_ASSERT_PARAM(_buf != NULL);
236
237 if (!_nbytes)
238 return *this;
239
240 if (!__bufSize) // == 0
241 {
242 // 버퍼링을 하지 않는다.
243 __write(__file, (const byte_t*)_buf, _nbytes);
244 return *this;
245 }
246
247 size_t n = (size_t)_nbytes;
248 const byte_t* buf = (const byte_t*)_buf;
249 size_t nCopySize = __bufSize - __dataSize;
250 if ((__dataSize > 0) || (nCopySize > n))
251 {
252 // 이미 버퍼링을 하고 있으면 버퍼를 채워서 write 하고
253 // 입력 데이터가 내부버퍼(__buf) 크기보다 작다면 버퍼링을 한다.
254 if (!__buf)
255 {
256 __buf = (byte_t*)malloc(__bufSize);
257 __DCL_ASSERT(__buf != NULL); // out of memory
258 }
259
260 if (nCopySize > n)
261 nCopySize = n;
262 memcpy(__buf + __dataSize, buf, nCopySize);
263 __dataSize += nCopySize;
264
265 buf += nCopySize;
266 n -= nCopySize;
267
268 if (__dataSize == __bufSize)
269 {
270 __write(__file, (const byte_t*)__buf, __dataSize);
271 __dataSize = 0;
272 }
273 }
274
275 if (n)
276 {
277 __DCL_ASSERT(__dataSize == 0);
278 // 남은 데이터가 있다.
279 // 버퍼링 후 남은 데이터 이거나
280 // 내부버퍼(__buf)의 크기가 <= n 인 경우이다.
281 // 블록단위로 wite하고 나머지는 내부버퍼에 복사한다.
282
283 size_t nBlockWrite = (n / __bufSize) * __bufSize;
284 nCopySize = n % __bufSize;
285 if (nBlockWrite)
286 {
287 size_t written = __write(__file, buf, nBlockWrite);
288 __DCL_ASSERT(written == nBlockWrite);
289 buf += written;
290// __DCL_TRACE1("RAW Write : %d\n", nRet);
291 }
292
293 if (nCopySize)
294 {
295 if (!__buf)
296 {
297 // 버퍼의 크기 <= n 인 경우 이전의 버퍼가 없을 수도 있다.
298 __buf = (byte_t*)malloc(__bufSize);
299 __DCL_ASSERT(__buf != NULL); // out of memory
300 }
301
302 memcpy(__buf, buf, nCopySize);
303 __dataSize += nCopySize;
304 }
305 }
306 return *this;
307}
308
309__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
#define __destroy__
Definition Config.h:363
wchar_t char_t
Definition Config.h:275
unsigned char byte_t
Definition Config.h:274
#define __DCL_THROWS1(e)
Definition Config.h:167
size_t __write(File *_file, const byte_t *_buf, size_t _nbytes)
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:376
#define __DCL_ASSERT_PARAM(expr)
Definition Object.h:384
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:228
#define __T(str)
Definition Object.h:44
#define __DCL_ASSERT_HANDLE(expr)
Definition Object.h:383
ByteString r
ByteBuffer * buf
void CharsetConvertException *size_t n
Definition SQLField.cpp:253
virtual void destroy()
Definition Exception.cpp:74
Definition File.h:38
virtual void close() __DCL_THROWS1(IOException *)
Definition File.cpp:363
virtual String toString() const
virtual size_t write(const void *_buf, size_t _n) __DCL_THROWS1(IOException *)
Definition File.cpp:535
void init(File *_pFile) __DCL_THROWS1(IOException *)
virtual String toString() const
virtual String toString() const
Definition Object.cpp:187
virtual void destroy()
Definition Object.cpp:192
String className() const
Definition Object.cpp:163
static void sleep(unsigned int _mills)
Definition Thread.cpp:150