11
11
12
12
final class File implements FileInterface
13
13
{
14
+ private const READ_CHUNK_FIZE = 65536 ;
15
+
14
16
use StatTrait;
15
17
16
18
private ExtUvLoop $ loop ;
@@ -36,41 +38,88 @@ public function stat(): PromiseInterface
36
38
public function getContents (int $ offset = 0 , ?int $ maxlen = null ): PromiseInterface
37
39
{
38
40
$ 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
+ }
46
65
});
47
66
});
48
- });
49
- });
67
+ };
68
+
69
+ return $ read ();
50
70
});
51
71
}
52
72
53
73
public function putContents (string $ contents , int $ flags = 0 )
54
74
{
55
75
$ 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 {
57
96
uv_fs_open (
58
97
$ this ->uvLoop ,
59
98
$ 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 );
69
103
}
70
104
);
71
105
});
72
106
}
73
107
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
+
74
123
public function unlink (): PromiseInterface
75
124
{
76
125
$ this ->activate ();
0 commit comments