今天复习了一下文件I/O,在看open函数的man手册时,看到了选项O_APPEND的说明,意思是每次写时都追加到文件的尾端。然后我心里就产生了几个小问题。
第一,用O_APPEND选项打开文件时,文件的初始偏移量为多少?
第二,在有O_APPEND选项的情况下,write之后,文件的偏移量又会是多少?
第三,在有O_APPEND选项的情况下,write之后,能不能用lseek调整文件偏移量以读取前面的内容?
为了解决上面三个问题,我写了下面的第一段代码。运行后得出答案。
首先,不管open打开文件的时候有没有使用O_APPEND选项,文件的初始偏移量都为0。假设write写入之前,文件偏移量的值为A,O_APPEND选项只是在write写入之前,把文件偏移量置为文件长度B,然后再执行写入操作,而写入操作完成后,文件偏移量并不会恢复为值A,而是继续在B的基础上增加实际写入的字节数。即使有O_APPEND选项存在,在write之后,仍然可以用lseek调整文件偏移量以用于读取前面的内容。因为O_APPEND只针对写操作,而且是只在每一次写操作之前把文件偏移量置为当前文件长度,并没有锁定文件偏移量不让修改。
然后我还写了第二段代码,用于检测自己是否真的理解了read,write,lseek,SEEK_SET,SEEK_CUR和SEEK_END对文件偏移量的影响。
第一段代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#define MAXSIZE 100
using std::cout;
using std::endl;
int main () {
char buf[MAXSIZE] = "Hello, this is a test.";
//新建一个文件a.txt
int fd = open ("a.txt", O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd == -1) {
perror ("open a.txt first error");
return EXIT_FAILURE;
}
//向文件中写入数据,然后关闭文件
int len = strlen (buf);
int n = write (fd, buf, len);
if (n != len) {
perror ("write error");
close (fd);
return EXIT_FAILURE;
}
cout << "\nSuccess to write " << n << " bytes data to the file : \"" << buf << "\"" << endl;
close (fd);
cout << "\n*****************************************\n" << endl;
//再次打开文件,以O_APPEND模式打开
fd = open ("a.txt", O_APPEND | O_RDWR);
if (fd == -1) {
perror ("open a.txt again error");
return EXIT_FAILURE;
}
//验证以O_APPEND模式打开时,初始偏移量是否还是0
char ch = 0;
cout << "File opened in O_APPEND, first read, then write, finally, back to the beginning of the file, read again.\n" << endl;
cout << "Before read, the offset is : " << lseek (fd, 0, SEEK_CUR) << endl;
n = read (fd, &ch, sizeof (ch));
if (n < 0) {
perror ("read error");
close (fd);
return EXIT_FAILURE;
}
cout << "Success to read \"" << ch << "\" from file." << endl;
cout << "After read, the offset is : " << lseek (fd, 0, SEEK_CUR) << "\n" << endl;
//验证以O_APPEND模式写入后,偏移量为文件尾
int tmp = write (fd, &ch, n);
if (tmp != n) {
perror ("write error");
close (fd);
return EXIT_FAILURE;
}
cout << "Success to write " << tmp << " bytes data to file : \"" << ch << "\"" << endl;
cout << "After write, the offset is : " << lseek (fd, 0, SEEK_CUR) << "\n" << endl;
lseek (fd, 0, SEEK_SET);
cout << "Change the file offset to value 0" << endl;
cout << "Before read, the offset is : " << lseek (fd, 0, SEEK_CUR) << endl;
n = read (fd, &ch, sizeof (ch));
if (n < 0) {
perror ("read error");
close (fd);
return EXIT_FAILURE;
}
cout << "Success to read \"" << ch << "\" from file." << endl;
cout << "After read, the offset is : " << lseek (fd, 0, SEEK_CUR) << endl;
close (fd);
return EXIT_SUCCESS;
}
第一段代码运行结果如下:
运算完这段代码后文件内容:
第二段代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#define MAXSIZE 100
using std::cout;
using std::endl;
int main () {
char buf[MAXSIZE] = "Hello, this is a test.";
char test[MAXSIZE] = "TEST";
//新建一个文件a.txt
int fd = open ("a.txt", O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd == -1) {
perror ("open a.txt first error");
return EXIT_FAILURE;
}
//向文件中写入数据,然后关闭文件
int len = strlen (buf);
int n = write (fd, buf, len);
if (n != len) {
perror ("write error");
close (fd);
return EXIT_FAILURE;
}
cout << "\nSuccess to write " << n << " bytes data to file : \"" << buf << "\"" << endl;
close (fd);
cout << "\n*****************************************\n" << endl;
//再次打开文件
fd = open ("a.txt", O_RDWR);
if (fd == -1) {
perror ("open a.txt again error");
return EXIT_FAILURE;
}
//输出文件未修改之前的内容
char ch = 0;
cout << "Before modifications, the file is : \"";
while ( (n = read (fd, &ch, sizeof (ch))) > 0)
cout << ch;
cout << "\"\n" << endl;
//输出ch
lseek (fd, 1, SEEK_SET);
n = read (fd, &ch, sizeof (ch));
if (n < 0) {
perror ("read error");
close (fd);
return EXIT_FAILURE;
}
cout << "Success to read \"" << ch << "\" from file." << endl;
//想想看test会覆盖掉哪一些内容
lseek (fd, 5, SEEK_CUR);
n = strlen (test);
int tmp = write (fd, test, n);
if (tmp != n) {
perror ("write error");
close (fd);
return EXIT_FAILURE;
}
cout << "Success to write " << tmp << " bytes data to file : \"" << test << "\"" << endl;
//想想看ch会是什么
n = read (fd, &ch, sizeof (ch));
if (n < 0) {
perror ("read error");
close (fd);
return EXIT_FAILURE;
}
cout << "Success to read \"" << ch << "\" from file." << endl;
//想想看5会覆盖在哪里
lseek (fd, -2, SEEK_END);
n = write (fd, "5", 1);
if (n != 1) {
perror ("write error");
close (fd);
return EXIT_FAILURE;
}
//输出修改后的文件内容
lseek (fd, 0, SEEK_SET);
cout << "\nAfter modifications, the file is : \"";
while ( (n = read (fd, &ch, sizeof (ch))) > 0)
cout << ch;
cout << "\"" << endl;
close (fd);
return EXIT_SUCCESS;
}
第二段代码运算结果如下: