1111
1212final class File implements FileInterface
1313{
14+ private const READ_CHUNK_FIZE = 65536 ;
15+
1416 use StatTrait;
1517
1618 private ExtUvLoop $ loop ;
@@ -36,41 +38,88 @@ public function stat(): PromiseInterface
3638 public function getContents (int $ offset = 0 , ?int $ maxlen = null ): PromiseInterface
3739 {
3840 $ this ->activate ();
39- return new Promise (function (callable $ resolve ) use ($ offset , $ maxlen ): void {
40- uv_fs_open ($ this ->uvLoop , $ this ->path . DIRECTORY_SEPARATOR . $ this ->name , UV ::O_RDONLY , 0 , function ($ fileDescriptor ) use ($ resolve , $ offset , $ maxlen ): void {
41- uv_fs_fstat ($ this ->uvLoop , $ fileDescriptor , function ($ fileDescriptor , array $ stat ) use ($ resolve , $ offset , $ maxlen ): void {
42- uv_fs_read ($ this ->uvLoop , $ fileDescriptor , $ offset , $ maxlen ?? (int )$ stat ['size ' ], function ($ fileDescriptor , string $ buffer ) use ($ resolve ): void {
43- $ resolve ($ buffer );
44- uv_fs_close ($ this ->uvLoop , $ fileDescriptor , function () {
45- $ this ->deactivate ();
41+ return $ this ->openFile (
42+ $ this ->path . DIRECTORY_SEPARATOR . $ this ->name ,
43+ UV ::O_RDONLY ,
44+ 0 ,
45+ )->then (
46+ function ($ fileDescriptor ) use ($ offset , $ maxlen ): PromiseInterface {
47+ $ buffer = '' ;
48+ $ read = function () use ($ fileDescriptor , $ offset , $ maxlen , &$ read , &$ buffer ) {
49+ return new Promise (function (callable $ resolve ) use ($ fileDescriptor , $ offset , $ maxlen , &$ read , &$ buffer ): void {
50+ uv_fs_read ($ this ->uvLoop , $ fileDescriptor , $ offset , $ maxlen ?? self ::READ_CHUNK_FIZE , function ($ fileDescriptor , string $ contents ) use ($ resolve , $ maxlen , &$ read , &$ buffer ): void {
51+ $ buffer .= $ contents ;
52+ $ bufferLength = strlen ($ buffer );
53+
54+ if ($ maxlen === null || $ bufferLength >= $ maxlen ) {
55+ if ($ maxlen !== null && $ bufferLength > $ maxlen ) {
56+ $ buffer = substr ($ buffer , 0 , $ maxlen );
57+ }
58+
59+ $ resolve ($ this ->closeOpenFile ($ fileDescriptor )->then (function () use ($ buffer ): string {
60+ return $ buffer ;
61+ }));
62+ } else {
63+ $ read ();
64+ }
4665 });
4766 });
48- });
49- });
67+ };
68+
69+ return $ read ();
5070 });
5171 }
5272
5373 public function putContents (string $ contents , int $ flags = 0 )
5474 {
5575 $ this ->activate ();
56- return new Promise (function (callable $ resolve ) use ($ contents , $ flags ): void {
76+ return $ this ->openFile (
77+ $ this ->path . DIRECTORY_SEPARATOR . $ this ->name ,
78+ (($ flags & \FILE_APPEND ) == \FILE_APPEND ) ? UV ::O_RDWR | UV ::O_CREAT | UV ::O_APPEND : UV ::O_RDWR | UV ::O_CREAT ,
79+ 0644 ,
80+ )->then (
81+ function ($ fileDescriptor ) use ($ contents ): PromiseInterface {
82+ return new Promise (function (callable $ resolve ) use ($ contents , $ fileDescriptor ): void {
83+ uv_fs_write ($ this ->uvLoop , $ fileDescriptor , $ contents , 0 , function ($ fileDescriptor , int $ bytesWritten ) use ($ resolve ): void {
84+ $ resolve ($ this ->closeOpenFile ($ fileDescriptor )->then (function () use ($ bytesWritten ): int {
85+ return $ bytesWritten ;
86+ }));
87+ });
88+ }
89+ );
90+ });
91+ }
92+
93+ private function openFile (string $ path , int $ flags , int $ mode ): PromiseInterface
94+ {
95+ return new Promise (function (callable $ resolve ) use ($ path , $ flags , $ mode ): void {
5796 uv_fs_open (
5897 $ this ->uvLoop ,
5998 $ this ->path . DIRECTORY_SEPARATOR . $ this ->name ,
60- (($ flags & \FILE_APPEND ) == \FILE_APPEND ) ? UV ::O_RDWR | UV ::O_CREAT | UV ::O_APPEND : UV ::O_RDWR | UV ::O_CREAT ,
61- 0644 ,
62- function ($ fileDescriptor ) use ($ resolve , $ contents , $ flags ): void {
63- uv_fs_write ($ this ->uvLoop , $ fileDescriptor , $ contents , 0 , function ($ fileDescriptor , int $ bytesWritten ) use ($ resolve ): void {
64- $ resolve ($ bytesWritten );
65- uv_fs_close ($ this ->uvLoop , $ fileDescriptor , function () {
66- $ this ->deactivate ();
67- });
68- });
99+ $ flags ,
100+ $ mode ,
101+ function ($ fileDescriptor ) use ($ resolve ): void {
102+ $ resolve ($ fileDescriptor );
69103 }
70104 );
71105 });
72106 }
73107
108+ private function closeOpenFile ($ fileDescriptor ): PromiseInterface
109+ {
110+ return new Promise (function (callable $ resolve ) use ($ fileDescriptor ) {
111+ try {
112+ uv_fs_close ($ this ->uvLoop , $ fileDescriptor , function () use ($ resolve ) {
113+ $ this ->deactivate ();
114+ $ resolve ();
115+ });
116+ } catch (\Throwable $ error ) {
117+ $ this ->deactivate ();
118+ throw $ error ;
119+ }
120+ });
121+ }
122+
74123 public function unlink (): PromiseInterface
75124 {
76125 $ this ->activate ();
0 commit comments