🌚

PHP流的操作

Posted at — Jun 01, 2015
#PHP #源码

实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/* reimplement fopen using stream */
ZEND_FUNCTION(donie_stream_fopen)
{
	php_stream *stream;
	char *path, *mode;
	int path_len, mode_len;
	int options = ENFORCE_SAFE_MODE|REPORT_ERRORS;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &path, &path_len, &mode, &mode_len) == FAILURE)
	{
		return;
	}

	stream = php_stream_open_wrapper(path, mode, options, NULL);
	if (!stream)
	{
		RETURN_FALSE;
	}

	php_stream_to_zval(stream, return_value);
}

php_stream_open_wrapper()是对文件类型资源创建流的方法,此外还有基于socket的流、目录流和特殊流三种。php_stream_to_zval()用于把流实例转换成zval结构。

创建文件类型的流

1
2
#define php_stream_open_wrapper(path, mode, options, opened)	_php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC)
#define php_stream_open_wrapper_ex(path, mode, options, opened, context)	_php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC TSRMLS_CC)

参数path是文件名或URL,mode是模式字符串,options是选项组合。php_stream_open_wrapper_ex()允许指定一个流的上下文。

options包含以下选项:

创建传输类型的流

1
php_stream *_php_stream_xport_create(const char *name, size_t namelen, int options, int flags, const char *persistent_id, struct timeval *timeout, php_stream_context *context, char **error_string, int *error_code)

参数:

flags:

创建目录类型的流

1
php_stream php_stream_opendir(const char *path, int options, php_stream_context *context)

创建特殊类型的流

1
2
3
4
5
php_stream *php_stream_fopen_tmpfile(void);
php_stream *php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path);
php_stream *php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id);
php_stream *php_stream_fopen_from_file(FILE *file, const char *mode);
php_stream *php_stream_fopen_from_pipe(FILE *file, const char *mode);

读流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 读一个字符
int php_stream_getc(php_stream *stream);

// 读取指定数量的字符
size_t php_stream_read(php_stream *stream, char *buf, size_t count);

// 读取直到行末、或流末、或最多maxlen个字符
char *php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, size_t *returned_len);
char *php_stream_gets(php_stream *stream, char *buf, size_t maxlen);

// 与php_stream_get_line相同,可指定截止标记
char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *returned_len, char *delim, size_t delim_len TSRMLS_DC);

// 读取一个目录项
php_stream_dirent *php_stream_readdir(php_stream *dirstream, php_stream_dirent *entry);

写流

1
2
3
4
5
6
7
8
9
// 写非阻塞流可能写入的数据比传入的短;_string要求传入的字符串以NULL结尾
size_t php_stream_write(php_stream *stream, char *buf, size_t count);
size_t php_stream_write_string(php_stream *stream, char *stf);

int php_stream_putc(php_stream *stream, int c);
// 与_string不同的是会自动追加一个换行符到字符串末尾
int php_stream_puts(php_string *stream, char *buf);

size_t php_stream_printf(php_stream *stream TSRMLS_DC, const char *format, ...);
1
int php_stream_flush(php_stream *stream);

在关闭流的时候,flush会被自动调用,并且大部分无过滤的流因无内部缓冲而不需flush,所以单独flush一般是不需要的。

寻址

1
2
3
4
int php_stream_seek(php_stream *stream, off_t offset, int whence);
int php_stream_rewind(php_stream *stream);
int php_stream_rewinddir(php_stream *dirstream);
off_t php_stream_tell(php_stream *stream);

offset是相对于whence的位移量,whence包含:

获取额外信息

1
int php_stream_stat(php_stream *stream, php_stream_statbuf *ssb);

关闭流

1
2
#define php_stream_close(stream) php_stream_free((stream), PHP_STREAM_FREE_CLOSE)
#define php_stream_pclose(stream) php_stream_free((stream), PHP_STREAM_FREE_CLOSE_PERSISTENT)

包含以下选项: