您的位置:首页 > 其它

文件I/O实践(1) --基础API

2015-12-25 17:36 176 查看

什么是I/O

输入/输出是内存和外设之间拷贝数据的过程:

设备->内存: 输入操作

内存->设备: 输出操作

高级I/O: ANSI C提供的标准I/O库函数成为高级I/O, 也称为带缓冲的I/O;

低级I/O: Linux 提供的系统调用, 通常也称为不带缓冲的I/O;

文件描述符

对于Linux内核而言, 所有的文件或设备都对应一个文件描述符(Linux的设计哲学: 一切皆文件), 这样可以简化系统编程的复杂程度;

当打开/创建一个文件的时候, 内核向进程返回一个文件描述符(是一个非负整数). 后续对文件的操作只需通过该文件描述符即可进行, 内核记录有关这个打开文件的信息;

一个进程启动时, 默认已经打开了3个文件, 标准输入(0, STDIN_FILENO), 标准输出(1, STDOUT_FILENO), 标准错误输出(2, STDERR_FILENO), 这些常量定义在unistd.h头文件中;

其中, 文件描述符基本上是与文件描述指针(FILE*)一一对应的, 如文件描述符0,1,2 对应 stdin, stdout, stderr;

文件指针与文件描述符的转换

fileno: 将文件指针转换成文件描述符

int fileno(FILE *stream);

fdopen: 将文件描述符转换成文件指针

FILE *fdopen(int fd, const char *mode);

[cpp] view
plaincopy





//示例

int main()

{

cout << "fileno(stdin) = " << fileno(stdin) << endl;

cout << "fileno(stdout) = " << fileno(stdout) << endl;

cout << "fileno(stderr) = " << fileno(stderr) << endl;

return 0;

}

文件I/O API

1.open

[cpp] view
plaincopy





#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

参数:

pathname: 文件名, 可以包含[绝对/相对]路径名;

flags: 文件打开模式;

mode: 用来指定对文件所有者, 文件用户组以及系统中的其他用户的访问权限;

注意: newMode = mode & ~umask

flags常用值



[cpp] view
plaincopy





//示例1

int main()

{

int fd = open("test.txt", O_RDONLY);

if (fd == -1)

{

cerr << "file open error, errno = " << errno <<

"\nstrerror: " << strerror(errno) << endl;

perror("perror");

exit(EXIT_FAILURE);

}

cout << "file open success" << endl;

}

[cpp] view
plaincopy





//示例2

inline void err_exit(std::string message)

{

perror(message.c_str());

exit(EXIT_FAILURE);

}

int main()

{

umask(0000);

int fd = open("test.txt", O_RDWR|O_CREAT|O_EXCL, 0666);

if (fd == -1)

err_exit("file open error");

else

cout << "file descriptor = " << fd << endl;

}

[附]

(1). umask API

//改变umask值

mode_t umask(mode_t mask);

(2). ulimit -a

查看系统中的各种限制;

其中-n: 查看一个进程所能够打开的最大文件数

(3). cat /proc/sys/fs/file-max

查看一个系统能够支持的最大打开文件数(该数与内存大小有关)

2.close

[cpp] view
plaincopy





#include <unistd.h>

int close(int fd);

关闭文件描述符, 使得文件描述符得以重新利用

3.read

[cpp] view
plaincopy





ssize_t read(int fd, void *buf, size_t count);

返回值:

错误: -1

到达文件尾: 0

成功: 返回从文件复制到规定缓冲区的字节数

4.wirte

[cpp] view
plaincopy





ssize_t write(int fd, const void *buf, size_t count);

返回值:

错误: -1

什么都没做: 0

成功: 返回成功写入文件的字节数

注意:

write返回大于0时, 并不代表buf的内容已经写入到磁盘上的文件中了, 其仅仅代表buf中的数据已经copy到相应的内核缓冲区了. 要实现将缓冲区的内容真正”冲洗”到磁盘上的文件, 需要调用fsync函数;

int fsync(int fd);

其将内核缓冲区中尚未写入磁盘的内容同步到文件系统中;

其实在open调用的时候也可以指定同步选项:O_SYNC O_SYNC The file is opened for synchronous I/O. Any write(2)s on the resulting file descriptor will block the calling process until the data has been physically written to the underlying hardware.

write会等到将buf的内容真正的写入到磁盘才真正返回;

[cpp] view
plaincopy





//示例: 带有O_SYNC选项

int main(int argc, char *argv[])

{

if (argc < 3)

{

cerr << "Usage : " << argv[0] << " src dest" << endl;

exit(EXIT_FAILURE);

}

int infd = open(argv[1], O_RDONLY);

if (infd == -1)

err_exit("file O_RDONLY error");

int outfd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0666);

if (outfd == -1)

err_exit("file O_WRONLY error");

char buf[1024];

int readBytes, writeBytes;

while ((readBytes = read(infd, buf, sizeof(buf))) > 0)

{

writeBytes = write(outfd, buf, readBytes);

cout << "readBytes = " << readBytes

<< ", writeBytes = " << writeBytes << endl;

}

}

文件的随机读写

5.lseek

对应于C库函数中的fseek, 通过指定相对于当前位置, 末尾位置或开始位置的字节数来重定位currp:

[cpp] view
plaincopy





off_t lseek(int fd, off_t offset, int whence);

返回值: 新的文件偏移值;

Whence取值:

SEEK_SET

The offset is set to offset bytes.

SEEK_CUR

The offset is set to its current location plus offset bytes.

SEEK_END

The offset is set to the size of the file plus offset bytes.

[cpp] view
plaincopy





//示例1

int main(int argc, char *argv[])

{

int fd = open("test.txt", O_RDONLY);

if (fd == -1)

err_exit("open error");

char buf[1024] = {0};

int readBytes = read(fd, buf, 5);

cout << "readBytes = " << readBytes << ", buf: " << buf << endl;

int seekCount = lseek(fd, 0, SEEK_CUR);

cout << "current offset = " << seekCount << endl;

}

[cpp] view
plaincopy





//示例2: 产生空洞文件

int main(int argc, char *argv[])

{

int fd = open("hole.txt", O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0666);

if (fd == -1)

err_exit("open error");

if (write(fd, "ABCDE", 5) == -1)

err_exit("first write error");

//创建一个1G的文件

if (lseek(fd, 1024*1024*1024, SEEK_CUR) == -1)

err_exit("lseek error");

if (write(fd, "Hello", 5) == -1)

err_exit("second write error");

close(fd);

}

[附]

-查看hole.txt文件

od -c hole.txt

cat -A hole.txt

-查看该文件大小

du -h hole.txt

du -b hole.txt

du -k hole.txt

du -m hole.txt

目录访问

6.opendir

[cpp] view
plaincopy





#include <sys/types.h>

#include <dirent.h>

DIR *opendir(const char *name);

返回值:

成功: 返回目录指针;

失败: 返回NULL;

7.readdir

[cpp] view
plaincopy





struct dirent *readdir(DIR *dirp);

返回值:

成功: 返回一个指向dirent结构的指针, 它包含指定目录的下一个连接的细节;

没有更多连接时, 返回0;

[cpp] view
plaincopy





struct dirent

{

ino_t d_ino; /* inode number */

off_t d_off; /* not an offset; see NOTES */

unsigned short d_reclen; /* length of this record */

unsigned char d_type; /* type of file; not supported

by all filesystem types */

char d_name[256]; /* filename */

};

8.closedir: 关闭目录

[cpp] view
plaincopy





int closedir(DIR *dirp);

[cpp] view
plaincopy





//示例: 简单的ls程序

int main(int argc, char *argv[])

{

if (argc < 2)

{

cerr << "Usage : " << argv[0] << " <directory>" << endl;

exit(EXIT_FAILURE);

}

DIR *dir = opendir(argv[1]);

if (dir == NULL)

err_exit("opendir error");

struct dirent *ent;

while ((ent = readdir(dir)) != NULL)

{

//过滤掉隐藏文件

if (ent->d_name[0] == '.')

continue;

cout << ent->d_name << "\ti-node: " << ent->d_ino

<< ", length: " << ent->d_reclen << endl;

}

closedir(dir);

}

9.mkdir

[cpp] view
plaincopy





int mkdir(const char *pathname, mode_t mode);

10.rmdir: 删除空目录

[cpp] view
plaincopy





int rmdir(const char *pathname);

11. Chmod, fchmod更改权限

[cpp] view
plaincopy





int chmod(const char *path, mode_t mode);

int fchmod(int fd, mode_t mode);

12.chown,fchown更改文件所有者/所属组

[cpp] view
plaincopy





int chown(const char *path, uid_t owner, gid_t
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: