DCL 3.7.4
Loading...
Searching...
No Matches
FileOutputStream.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#ifdef __WINNT__
4 #include <windows.h>
5#else
6 #include <errno.h>
7 #include <unistd.h> // isatty
8 #include <sys/stat.h> // fstat
9#endif
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_HAVE_THIS_FILE__
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#ifdef __WINNT__
54 switch (_file->fileType()) {
55 case File::REGULAR: {
56 __bufSize = 4096;
57 break;
58 }
59 case File::PIPE: {
60 DWORD dwOutBufferSize = 0;
61 if (GetNamedPipeInfo(_file->handle(), NULL, &dwOutBufferSize, NULL, NULL)) {
62 __bufSize = dwOutBufferSize;
63 }
64 break;
65 }
66 default: {
67 // __bufSize = 0;
68 }
69 }
70#else
71 if (!isatty(_file->handle())) {
72 struct stat st;
73 if (fstat(_file->handle(), &st)) {
74 throw new IOException(_file->path(), errno);
75 }
76 __bufSize = st.st_blksize;
77 }
78#endif
79 __dataSize = 0;
80}
81
82FileOutputStream::FileOutputStream(File& _file)
84{
85 init(&_file);
86 __file = &_file;
87 __closeDestroy = false;
88}
89
90FileOutputStream::FileOutputStream(File::HandleType _handle)
92{
93 File* file = new File(_handle, 0, false);
94 try {
95 init(file);
96 }
97 catch (Exception* _e) {
98 delete file;
99 throw _e;
100 }
101 __file = file;
102 __closeDestroy = true;
103}
104
105FileOutputStream::FileOutputStream(File* __destroy__ _file)
107{
108 __DCL_ASSERT(_file != NULL);
109 try {
110 init(_file);
111 }
112 catch (Exception* _e) {
113 delete _file;
114 throw _e;
115 }
116 __file = _file;
117 __closeDestroy = true;
118}
119
120void FileOutputStream::open(const String& _path, bool _truncate)
122{
123 if (__file)
124 close();
125
126 File* file = new File(_path, File::WRITEONLY | File::CREATE
127 | (_truncate ? File::TRUNCATE : File::APPEND));
128 try {
129 init(file);
130 }
131 catch (Exception* _e) {
132 delete file;
133 throw _e;
134 }
135 __file = file;
136 __closeDestroy = true;
137}
138
139FileOutputStream::~FileOutputStream()
140{
141 if (__file != NULL) {
142 try {
143 close();
144 }
145 catch (IOException* _e) {
146 __DCL_TRACE1(L"~FileOutputStream close error! %ls\n", _e->toString().data());
147 _e->destroy();
148 }
149 }
151}
152
153void FileOutputStream::close()
155{
157 Exception* e = NULL;
158 try {
159 flush();
160 }
161 catch (Exception* _cause) {
162 e = _cause;
163 }
164
165 if (__buf) {
166 free(__buf);
167 __buf = NULL;
168 __bufSize = 0;
169 __dataSize = 0;
170 }
171
172 File* file = __file;
173 __file = NULL;
174 if (__closeDestroy) {
175 try {
176 file->close();
177 }
178 catch (Exception* _cause) {
179 if (!e)
180 e = _cause;
181 else
182 _cause->destroy();
183 }
184 file->destroy();
185 }
186 if (e) {
187 throw e;
188 }
189}
190
191inline size_t __write(File* _file, const byte_t* _buf, size_t _nbytes)
192{
193 size_t written = 0;
194 while (_nbytes) {
195 size_t n = _file->write(_buf + written, _nbytes);
196 if (n) {
197 written += n;
198 _nbytes -= n;
199 }
200 else {
201 // errno == EAGAIN
202 // retry after 10 milliseconds
203 Thread::sleep(10);
204 }
205 }
206 return written;
207}
208
209void FileOutputStream::flush()
211{
213 if (__dataSize) {
215 __dataSize = 0;
216 }
217}
218
219OutputStream& FileOutputStream::write(const void* _buf, size_t _nbytes)
221{
222 __DCL_ASSERT_HANDLE(__file != NULL);
223 __DCL_ASSERT_PARAM(_buf != NULL);
224
225 if (!_nbytes) {
226 return *this;
227 }
228 if (!__bufSize) {
229 // 버퍼링을 하지 않는다.
230 __write(__file, (const byte_t*)_buf, _nbytes);
231 return *this;
232 }
233
234 size_t n = (size_t)_nbytes;
235 const byte_t* buf = (const byte_t*)_buf;
236 size_t nCopySize = __bufSize - __dataSize;
237 if ((__dataSize > 0) || (nCopySize > n)) {
238 // 이미 버퍼링을 하고 있으면 버퍼를 채워서 write 하고
239 // 입력 데이터가 내부버퍼(__buf) 크기보다 작다면 버퍼링을 한다.
240 if (!__buf) {
241 __buf = (byte_t*)malloc(__bufSize);
242 __DCL_ASSERT(__buf != NULL); // out of memory
243 }
244
245 if (nCopySize > n)
246 nCopySize = n;
247 memcpy(__buf + __dataSize, buf, nCopySize);
248 __dataSize += nCopySize;
249
250 buf += nCopySize;
251 n -= nCopySize;
252 if (__dataSize == __bufSize) {
253 __write(__file, (const byte_t*)__buf, __dataSize);
254 __dataSize = 0;
255 }
256 }
257
258 if (n) {
259 __DCL_ASSERT(__dataSize == 0);
260 // 남은 데이터가 있다.
261 // 버퍼링 후 남은 데이터 이거나
262 // 내부버퍼(__buf)의 크기가 <= n 인 경우이다.
263 // 블록단위로 wite하고 나머지는 내부버퍼에 복사한다.
264 size_t nBlockWrite = (n / __bufSize) * __bufSize;
265 nCopySize = n % __bufSize;
266 if (nBlockWrite) {
267 size_t written = __write(__file, buf, nBlockWrite);
268 __DCL_ASSERT(written == nBlockWrite);
269 buf += written;
270// __DCL_TRACE1("RAW Write : %d\n", nRet);
271 }
272
273 if (nCopySize) {
274 if (!__buf) {
275 // 버퍼의 크기 <= n 인 경우 이전의 버퍼가 없을 수도 있다.
276 __buf = (byte_t*)malloc(__bufSize);
277 __DCL_ASSERT(__buf != NULL); // out of memory
278 }
279
280 memcpy(__buf, buf, nCopySize);
281 __dataSize += nCopySize;
282 }
283 }
284 return *this;
285}
286
287__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:312
#define __destroy__
Definition Config.h:334
wchar_t char_t
Definition Config.h:247
unsigned char byte_t
Definition Config.h:246
#define __DCL_THROWS1(e)
Definition Config.h:152
size_t __write(File *_file, const byte_t *_buf, size_t _nbytes)
IOException *size_t r
Definition MediaInfo.cpp:82
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:399
#define __DCL_ASSERT_PARAM(expr)
Definition Object.h:409
#define __DCL_ASSERT(expr)
Definition Object.h:394
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:245
#define __T(str)
Definition Object.h:60
#define __DCL_ASSERT_HANDLE(expr)
Definition Object.h:408
virtual void destroy()
Definition Exception.cpp:74
Definition File.h:42
virtual void close() __DCL_THROWS1(IOException *)
Definition File.cpp:369
virtual String toString() const
virtual size_t write(const void *_buf, size_t _n) __DCL_THROWS1(IOException *)
Definition File.cpp:541
void init(File *_file) __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:152