DCL 4.0
Loading...
Searching...
No Matches
FileInputStream.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/size_t.h>
14#include <dcl/Object.h>
15#include <dcl/FileInputStream.h>
16
17#if __DCL_HAVE_ALLOC_DEBUG
18#undef __DCL_ALLOC_LEVEL
19#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
20#endif
21
22#undef __THIS_FILE__
23static const char_t __THIS_FILE__[] = __T("dcl/FileInputStream.cpp");
24
25__DCL_BEGIN_NAMESPACE
26
28
29String FileInputStream::toString() const
30{
31 StringBuilder r = className();
32 if (__file)
33 r += __T("(") + __file->toString() + __T(")");
34 else
35 r += __T(" closed");
36 return r;
37}
38
39FileInputStream::FileInputStream(const String& _path)
41{
42 __file = NULL;
43 open(_path);
44}
45
46#ifdef _MSC_VER
47FileInputStream::FileInputStream(const wchar_t* _path)
49{
50 __file = NULL;
51 open(_path);
52}
53#endif
54
57{
58 __buf = NULL;
59 __bufSize = 0;
60#if __DCL_WINDOWS
61 switch (_pFile->fileType())
62 {
63 case File::REGULAR:
64 __bufSize = 4096;
65 break;
66#if 0
67 case File::PIPE:
68 {
69 DWORD dwInBufferSize = 0;
70 if (GetNamedPipeInfo(_pFile->handle(), NULL, NULL, &dwInBufferSize, NULL))
71 __bufSize = dwInBufferSize;
72 }
73 break;
74#endif
75 }
76
77#else
78 struct stat st;
79 if (fstat(_pFile->handle(), &st)) // = -1
80 throw new IOException(__file->path(), errno);
81 if (S_ISBLK(st.st_mode))
82 __bufSize = st.st_blksize;
83
84#endif
86 __cacheSize = 0;
87}
88
89FileInputStream::FileInputStream(File& _file)
91{
92 init(&_file);
93 __file = &_file;
94 __closeDestroy = false;
95}
96
97FileInputStream::FileInputStream(File::HandleType _handle)
99{
100 File* pFile = new File(_handle, 0, false);
101 try
102 {
103 init(pFile);
104 }
105 catch (Exception* e)
106 {
107 delete pFile;
108 throw e;
109 }
110 __file = pFile;
111 __closeDestroy = true;
112}
113
114void FileInputStream::open(const String& _path)
116{
117 if (__file)
118 close();
119
120 File* pFile = new File(_path, File::READONLY);
121 try
122 {
123 init(pFile);
124 }
125 catch (Exception* e)
126 {
127 delete pFile;
128 throw e;
129 }
130 __file = pFile;
131 __closeDestroy = true;
132}
133
134FileInputStream::~FileInputStream()
135{
136 if (__file != NULL)
137 {
138 try
139 {
140 close();
141 }
142 catch (IOException* e)
143 {
144 __DCL_TRACE1(L"!FileInputStream close error! %ls\n",
145 e->toString().data());
146 e->destroy();
147 }
148 }
150}
151
152void FileInputStream::close()
154{
156
157 if (__buf)
158 {
159 free(__buf);
162 }
163
164 Exception* e = NULL;
165 File* file = __file;
166 __file = NULL;
167 if (__closeDestroy)
168 {
169 try
170 {
171 file->close();
172 }
173 catch (Exception* cause)
174 {
175 e = cause;
176 }
177 file->destroy();
178 }
179 if (e)
180 throw e;
181}
182
183size_t FileInputStream::available()
185{
187
188 return __ADD_OVERFLOW_MAX(__file->available(), __cacheSize);
189}
190
191size_t FileInputStream::read(void* _buf, size_t _nbytes)
193{
194 __DCL_ASSERT_HANDLE(__file != NULL);
195 __DCL_ASSERT_PARAM(_buf != NULL);
196
197 if (!_nbytes)
198 return 0;
199
200 if (!__bufSize) // == 0
201 {
202 // 버퍼링을 하지 않는다.
203 return __file->read(_buf, _nbytes);
204 }
205
206 size_t nbytes = _nbytes;
207 byte_t* buf = (byte_t*)_buf;
208
209 if (__cacheSize)
210 {
211 __DCL_ASSERT(__buf != NULL);
212 __DCL_ASSERT(__cacheStart != NULL);
213
214 size_t nCopy = __MIN(__cacheSize, nbytes);
215 memcpy(buf, __cacheStart, nCopy);
216 __cacheStart += nCopy;
217 __cacheSize -= nCopy;
218
219 buf += nCopy;
220 nbytes -= nCopy;
221 }
222
223 if (nbytes)
224 {
225 // 이미 캐시되어 있는 데이터는 복사했다.
226 __DCL_ASSERT(__cacheSize == 0);
227
228 // Non-Block이 가능한 양만큼 __file에서 직접 읽는다.
229 size_t nAvail = (__MIN(nbytes, __file->available()) / __bufSize) * __bufSize;
230 if (nAvail)
231 {
232 size_t nRead = __file->read(buf, nAvail);
233 if (nRead)
234 {
235 buf += nRead;
236 nbytes -= nRead;
237 nAvail -= nRead;
238 }
239 }
240
241 if (!nAvail)
242 {
243 // Non-Block에서 읽을 것이 없었거나, 또는 모두 읽었다면 더 읽는다.
244 // Non-Block에서 요구된 것 보다 덜 읽었다면 다음을 실패할 가능성이 높다.
245 size_t nCacheRead = nbytes % __bufSize;
246 if (nCacheRead)
247 {
248 if (!__buf)
249 {
250 __buf = (byte_t*)malloc(__bufSize);
251 __DCL_ASSERT(__buf != NULL); // out of memory
252 }
253
254 // 이곳에서 Block 될 수 있다.
255 size_t nRead = __file->read(__buf, __bufSize);
256 if (nRead)
257 {
258 // __DCL_TRACE2("CacheRead : %d, %d\n", __bufSize, nRead);
259 __cacheStart = __buf;
260 __cacheSize = nRead;
261
262 size_t nCopy = __MIN(__cacheSize, nbytes);
263 memcpy(buf, __cacheStart, nCopy);
264 __cacheStart += nCopy;
265 __cacheSize -= nCopy;
266
267 // buf += nCopySize;
268 nbytes -= nCopy;
269 }
270 }
271 }
272 }
273
274 return _nbytes - nbytes;
275}
276
277__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
wchar_t char_t
Definition Config.h:275
unsigned char byte_t
Definition Config.h:274
#define __DCL_THROWS1(e)
Definition Config.h:167
#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
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
void init(File *_pFile)
const byte_t * __cacheStart
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
size_t __MIN(size_t x, size_t y)
Definition size_t.h:27
__DCL_BEGIN_NAMESPACE size_t __ADD_OVERFLOW_MAX(size_t x, size_t y)
Definition size_t.h:18