📄 5.txt
字号:
5.文件处理
当我们要处理文件时,我们必需先调用apr_file_open()函数,这儿是它的原型声明:
/* 摘自apr_file_io.h */
APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **newf, const char *fname,
apr_int32_t flag, apr_fileperms_t perm,
apr_pool_t *pool);
第一个参数是结果参数,其类型为apr_file_t**,即通过调用apr_file_open()来创建一个apr_file_t对象。第二个参数是文件路径,第三个参数是位标志,在apr_file_io.h文件中定义。第四个参数是对新创建的文件设置的访问权限,其值是也是位标志,在apr_file_io.h中定义。例如,如果你想创建一个访问权限为0600的文件,只有文件拥有者可以读写它,那么你可以指定其值为APR_UREAD|APR_UWRITE。在通常情况下,文件访问权限的值你可以设置为APR_OS_DEFAULT。第五个参数是要使用的内存池,毋庸置疑,你得使用apr_pool_create()函数去事先创建它。
打开文件后,我们就可以使用其他的API函数来处理文件了,这些API函数可以在apr_file_io.h文件中找到。基本的有apr_file_read()和apr_file_write()函数,如你所想,apr_file_read()使我们可以从文件中读取一些东西,而apr_file_write()允许我们向文件写入一些东西,其函数原型声明如下:
/* 摘自apr_file_io.h */
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf,
apr_size_t *nbytes);
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf,
apr_size_t *nbytes);
这两个函数的第三个参数均为输入输出参数,意思是说,在调用函数时我们指定它的值为输入值的长度,而在函数返回时它的值为结果的长度。具体而言,apr_file_read()返回的是读取字节的长度,apr_file_write()返回的是写入字节的长度。这儿有一个例子:
/* 关于apr_file_write()的伪代码 */
strcpy(outbuf, "123456789");
apr_size_t outlen = strlen(outbuf);
rv = apr_file_write(fp, outbuf, &outlen);
printf("apr_file_write() rv = %d, nbytes = %d\n", rv, outlen);
这个例子中,在调用apr_file_write()之前,变量'outlen'的值是9,通过使用&outlen这样的形式作为第三个参数,告诉
apr_file_write()函数可写的长度是9,当apr_file_write()函数返回时,'outlen'的值变为实际写入的长度。如果是本地文件,它的值常常是9,理论上,它的值可以变小(例如当磁盘满的时候)。
我们只能调用apr_file_close()函数去关闭文件,除此之外,也可以通过销毁apr_file_open()函数相关的内存池来实现文件的关闭。我比较喜欢显式地调用apr_file_close()函数去关闭文件,不过这仅仅是我的意见。
注:在不同的libapr版本之间存在着一些源程序的兼容性问题,apr_file_open()的第三个参数自libapr 1.1.0版本这后加上了APR_FOPEN_前缀,但是之前的版本却没有这个前缀。可以使用APR_FOPEN_CREATE代替APR_CREATE,请查阅你使用的libapr版本的apr_file_io.h文件。同样地,apr_file_open()的第四个参数自libapr 1.1.0版本之后,添加了APR_FPROT_前缀。
注:这儿还有一个兼容性的问题是关于文件路径分割符的,Unix(POSIX)系统使用斜线('/'),MS-Windows使用反斜线('\')作为分割符。如果你要写一个能在Unix和MS-Windows系统上都能运行的应用程序,我推荐你统一地在文件路径中使用斜线('/')作为分割符,因为MS-Windows中可以接受识别它。
注:特别注意apr_file_gets()的用法,没有APR_BUFFERED的apr_file_gets()调用而将很大的影响效率,这是因为apr_file_gets()内部将对每一个字节都会调用apr_file_read()。记住要使用apr_file_gets()时,打开文件必须加上APR_BUFFERED标志。
在以下的情况我不推荐你使用APR_BUFFERED标志:
1.当你使用mmap映射一个文件时(因为当mmap一个APR_BUFFERED文件时会产生错误)
2.没有读/写(例如仅仅是为了锁住一个文件)
3.你能确定你使用一个大内存缓冲区来读/写文件。
注:当使用APR_BUFFERED标志打开了一个文件并且对一个文件调用apr_file_trunc()函数时,你必须在调用apr_file_trunc()之前调用apr_file_flush()之前,否则,文件将被损坏。
注: 当使用APR_BUFFERED标志打开了一个文件并且这个文件被多个线程共享,那么APR_XTHREAD标志也是必需的。不幸的是,APR_XTHREAD标志在Windows系统有另一面的影响,我的经验告诉我不要在Windows系统中使用APR_XTHREAD标志。
可以得到文件的各种信息,例如大小,时间,拥有者,访问权限等等,这些信息存放在apr_finfo_t结构体中,apr_finfo_t在文件apr_file_info.h中有定义。这里有两个相关的API函数:
/* 摘自 apr_file_io.h */
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted, apr_file_t *thefile);
/* 摘自 apr_file_info.h */
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, apr_int32_t wanted, apr_pool_t *pool);
apr_file_info_get()函数要求apr_file_t对象,apr_stat()函数要求文件路径。如果已经打开了文件并且生成了apr_file_t对象,那么最好使用apr_file_info_get();否则,可以调用apr_stat()。与其他类型不同,apr_finfo_t是一个完整类型,这两个api函数并没有生成该对象,我们只能显式地创建它并为其分配内存。典型地,它在当前栈中创建,这是因为我们想知道一些诸如文件大小和时间的属性。注意如apr_finfo_t::fname等一些内存,如果是创建在内存池中的,这将产生一些错误。请查看finfo-sample.c文件,了解它的用法。
有一些文件处理函数是在文件名基础上运行的,例如apr_file_remove()和apr_file_copy(),它们在apr_file_io.h和arp_file_info.h文件中能找到。
注:一些API函数带有"wanted"参数, 通过指定该参数的位标志得到文件的属性。 这些函数是apr_dir_read(), apr_stat(), apr_lstat()和apr_file_info_get()。注意"wanted"参数的值将会超出操作系统的文件系统的支持,在这种情况下,该API函数将返回APR_INCOMPLETE。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -