1.2基于Linux的文件操作
在Linux里,socket被视为文件的一种,因此在网络传输过程中可以使用文件I/O的函数。
而Windows区分文件和socket,因此需要调用特殊的数据传输函数
底层文件访问(Low-Level File Access)和文件描述符(File Descripter)
文件描述符是操作系统分配给文件或套接字的整数
文件和套接字一般经过创建过程后才会被分配文件描述符。有三种特殊的对象,即使未经过创建过程,程序开始运行后也会被自动分配文件描述符。
文件描述符 | 对象 |
---|---|
0 | 标准输入:Standard Input |
1 | 标准输出:Standard Output |
2 | 标准错误:Standard Error |
打开文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(const char *path,int flag);
成功时返回文件描述符,失败时返回-1
path: 文件名的字符串地址
flag: 文件打开模式信息
打开模式 | 含义 |
---|---|
O_CREATE | 必要时创建文件 |
O_TRUNC | 删除全部数据 |
O_APPEND | 维持现有数据,保存到其后面 |
O_RDONLY | 只读打开 |
O_WRDONLY | 只写打开 |
O_RDWR | 读写打开 |
关闭文件
#include<unistd.h>
int close(int fd);
成功时返回0,失败时返回-1
fd: 需要关闭的文件或套接字的文件描述符
注意: 此函数不仅可以关闭文件,还可以关闭套接字。
将数据写入文件
#include<unistd.h>
ssize_t write(int fd,const void * buf,size_t nbytes);
成功时返回写入的字节数,失败时返回-1
fd: 数据传输对象的文件描述符
buf: 保存要传输的数据的缓冲地址值
nbytes: 要传输数据的字节数
创建新文件并保存数据的完整程序:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void error_handling(char* message);
int main(void)
{
int fd;
char buf[]="Let's go!\n";
fd=open("data.txt", O_CREAT|O_WRONLY|O_TRUNC);
if(fd==-1)
error_handling("open() error!");
printf("file descriptor: %d \n", fd);
if(write(fd, buf, sizeof(buf))==-1)
error_handling("write() error!");
close(fd);
return 0;
}
void error_handling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
第13行:文件打开模式为O_CREAT|O_WRONLY|O_TRUNC组合,表示创建空文件,并只能写,若已有同名文件则清空全部数据
第18行:向fd中保存的文件描述符对应的文件传输buf中保存的数据
Linux下运行结果:
读取文件中的数据
#include<unistd.h>
ssize_t read(int fd,void * buf,size_t nbytes);
fd: 显示数据接收对象的文件描述符
buf: 要保存接收数据的缓冲地址
nbytes: 要接受数据的最大字节数
读取文件中的数据 完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define BUF_SIZE 100
void error_handling(char* message);
int main(void)
{
int fd;
char buf[BUF_SIZE];
fd=open("data.txt", O_RDONLY);
if( fd==-1)
error_handling("open() error!");
printf("file descriptor: %d \n" , fd);
if(read(fd, buf, sizeof(buf))==-1)
error_handling("read() error!");
printf("file data: %s", buf);
close(fd);
return 0;
}
void error_handling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
第15行: 打开读取文件专用的文件data.txt
第21行: 调用read函数,向buf数组保存读入的数据
以上是基于文件描述符的I/O操作
文件描述符和套接字
下面是同时创建文件和套接字,并用整数型态比较返回的文件描述符值的完整代码(综合以上创建文件描述符、创建文件的知识点)
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
int main(void)
{
int fd1, fd2, fd3;
fd1=socket(PF_INET, SOCK_STREAM, 0);
fd2=open("test.dat", O_CREAT|O_WRONLY|O_TRUNC);
fd3=socket(PF_INET, SOCK_DGRAM, 0);
printf("file descriptor 1: %d\n", fd1);
printf("file descriptor 2: %d\n", fd2);
printf("file descriptor 3: %d\n", fd3);
close(fd1);
close(fd2);
close(fd3);
return 0;
}
第9行:创建TCP连接的套接字
第11行:创建UDP连接的套接字
第10行:创建test.dat文件
第17-19行:输出上面创建的三个文件描述符的整数值
运行结果
从输出的文件描述符可以看出,描述符从3开始以由小到大的顺序编号
编号0、1、2是分配给标准I/O的描述符