Linux c下文件读写可用creat,open,close,read,write,lseek等函数。对于跨平台的程序还是用C标准库的fopen等。
open
#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);
第一个参数是文件名,第二个参数是打开文件的方式
flags:
O_RDONLY: 只读打开文件。
以只读方式打开文件。O_WRONLY: 只写打开文件。
以只写方式打开文件。O_RDWR: 读写方式打开文件。
以读写方式打开文件。O_CREAT: 如果文件不存在,则创建文件。
如果文件不存在,则创建文件。O_EXCL: 与O_CREAT一起使用,用于确保文件是新创建的。如果文件已存在且O_EXCL标志被指定,则open会失败。
O_TRUNC: 如果文件存在且以写方式打开,则将文件截断为零长度。
O_APPEND: 在文件末尾追加数据。
O_NONBLOCK: 非阻塞模式。使用此标志,文件描述符将以非阻塞方式打开,读写操作不会阻塞进程。
O_SYNC: 打开文件以同步写入方式。所有写入操作将立即写入物理介质。
前三个方式互斥,但可以与后面的进行或运算
mode
参数用于指定新文件的权限,它是一个三位的八进制数字,每一位表示不同的权限。这个参数通常与O_CREAT
标志一起使用,以确保新文件被创建时有适当的权限设置。以下是一些常见的权限位和它们的含义:
S_IRUSR (0400): 用户(文件所有者)具有读权限。 中文:用户(文件所有者)具有读权限。
S_IWUSR (0200): 用户具有写权限。
S_IXUSR (0100): 用户具有执行权限。
S_IRGRP (0040): 组具有读权限。
S_IWGRP (0020): 组具有写权限。
S_IXGRP (0010): 组具有执行权限。
S_IROTH (0004): 其他用户具有读权限。
S_IWOTH (0002): 其他用户具有写权限。
S_IXOTH (0001): 其他用户具有执行权限。
这些权限位可以通过按位或运算组合在一起,以设置文件的权限。例如,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
表示文件所有者具有读写权限,而组和其他用户只有读权限。在
mode
参数中,这些权限位可以使用宏来表示,如S_IRWXU
表示用户有读、写和执行权限。这有助于提高代码的可读性。
成功调用open会返回一个文件描述符,若有错误则返回-1,并把错位代码赋给errno。
creat
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat (const char *pathname, mode t mode);
creat
系统调用用于以只写方式打开文件,并在文件不存在时创建它。它相当于使用open
调用,其中包括了O_WRONLY | O_CREAT | O_TRUNC
标志。
pathname
:包含文件路径的字符串。mode
:文件权限位(类似于open
系统调用中的mode
参数)。返回值
成功时,
creat
返回一个非负整数,它是与新创建或已打开文件关联的文件描述符。失败时返回-1,并设置errno
以指示错误。
close
#include <unistd.h>
int close(int fd);
close
函数关闭一个先前由open
或creat
打开的文件描述符。关闭文件描述符后,它将不再指向任何文件,且不能再用于读取或写入。
fd
:要关闭的文件描述符。
示例程序1
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<cstdlib>
int main(){
int fd;
//打开文件,文件不存在自动创建,文件存在则出错,文件所有者有读写权限
if((fd=open("example_62.c",O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1){
perror("open");
//printf("open:%s with errno:%d\n",strerror(errno),errno);
exit(1);
}else{
printf("create file success\n");
}
close(fd);
return 0;
}
第一次运行
成功创建。再一次运行呢?
错误,因为O_EXCL被设置。
顺便,了解一下上面头文件的作用
sys/types.h:
- 包含各种基本数据类型的定义,如
size_t
和pid_t
。- 通常用于定义与系统相关的数据类型。
sys/stat.h:
- 包含文件状态信息的结构体定义,如
struct stat
。- 提供了文件权限位的宏定义,如
S_IRUSR
和S_IWGRP
。- 用于获取和设置文件的状态信息。
fcntl.h:
- 定义了文件控制操作所需的常量,如
O_RDONLY
和O_WRONLY
。- 提供了
open
函数和一些文件控制操作函数的声明。- 用于打开、关闭、复制和其他文件操作。
unistd.h:
- 提供了 POSIX 系统调用的声明,如
read
、write
和close
。- 包含一些常用的符号常量,如
STDIN_FILENO
、STDOUT_FILENO
和STDERR_FILENO
。- 用于实现对文件描述符的基本 I/O 操作。
errno.h:
- 定义了
errno
全局变量,该变量在系统调用失败时被设置为指示错误的整数值。- 包含一些与错误码相关的宏定义,如
EACCES
和EINVAL
。- 用于检查和处理系统调用产生的错误。
这些头文件通常用于系统级编程,允许开发者使用系统调用和低级 I/O 操作。在编写需要直接与文件系统、进程控制等打交道的程序时,这些头文件是必需的。
read
#include <unistd.h>
ssize_t read(int fd, void *buf, sizet count);
fd (file descriptor):
- 文件描述符,它是一个非负整数,用于标识已打开文件或 I/O 设备。通常由
open
函数返回。- 表示从哪个文件或设备读取数据。
buf (buffer):
- 指向用于存放读取数据的缓冲区的指针。
buf
必须是一个有效的内存地址,足够大以容纳要读取的数据。count (size_t):
- 期望读取的字节数。
count
参数指定了buf
缓冲区的大小,即期望从文件中读取的字节数。返回值 (ssize_t):
- 返回值是已经成功读取的字节数。如果到达文件末尾(EOF),返回值为 0。
- 如果出现错误,返回值为 -1,并且
errno
被设置以指示错误的原因。
最好能将返回值与参数count进行比较,若比count少,则可能是读到文件尾或读取被中断。
读写指针会跟着移动
wtire
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd (file descriptor):
- 文件描述符,是一个非负整数,用于标识已打开文件或 I/O 设备。通常由
open
函数返回。- 表示写入数据的目标文件或设备。
buf (buffer):
- 指向包含待写入数据的缓冲区的指针。
buf
必须是一个有效的内存地址,包含要写入的数据。count (size_t):
- 要写入的字节数。
count
参数指定了buf
缓冲区中的数据大小,即要写入的字节数。返回值 (ssize_t):
- 返回已经成功写入的字节数。如果写入失败,返回值为 -1,并且
errno
被设置以指示错误的原因。
lseek
用来移动文件读写指针的位置
#include<sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd (file descriptor):
- 文件描述符,是一个非负整数,用于标识已打开文件或 I/O 设备。通常由
open
函数返回。- 表示要操作的文件。
offset (off_t):
- 偏移量,是一个有符号整数,指定了文件偏移的目标位置。
- 如果
whence
参数是SEEK_SET
,则offset
表示从文件开始处的偏移量;如果是SEEK_CUR
,则offset
表示从当前文件偏移处的偏移量;如果是SEEK_END
,则offset
表示从文件末尾处的偏移量。whence (int):
- 定位基准,指定了偏移量的计算方式。可以是
SEEK_SET
、SEEK_CUR
或SEEK_END
。SEEK_SET
表示从文件开始处计算偏移,SEEK_CUR
表示从当前位置计算偏移,SEEK_END
表示从文件末尾处计算偏移。返回值 (off_t):
- 返回新的读写指针距离文件开始处的偏移量。如果出现错误,返回值为 -1,并且
errno
被设置以指示错误的原因。
示例程序2
演示文件读写和文件读写指针的移动操作过程
#include<iostream>
#include<cstring>
#include <cstdio>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
using namespace std;
//自定义的错误处理函数
void my_err(const char *err_string,int line){
fprintf(stderr,"line:%d ",line);
perror(err_string);
exit(1);
}
//自定义的读数据函数
int my_read(int fd){
int len;
int ret;
int i;
char read_buf[64];
//获得文件长度
if(lseek(fd,0,SEEK_END)==-1)//首先偏移指针移动到文件末尾
my_err("lseek",__LINE__);
if((len=lseek(fd,0,SEEK_CUR))==-1)//函数返回距离开头的偏移量大小,因为现在指针已经在末尾,SEEK_CUR==SEEK_END,这样函数返回的偏移量就是文件的长度
my_err("lseek",__LINE__);
if((lseek(fd,0,SEEK_SET))==-1)//把偏移指针回到开头,不会影响后续的读写
my_err("lseek",__LINE__);
printf("len:%d\n",len);
//读
if((ret=read(fd,read_buf,len))<0)
my_err("read",__LINE__);//读操作出错
for(i=0;i<len;i++)
printf("%c",read_buf[i]);//打印读取的内容
printf("\n");
return ret;
}
int main(){
int fd;
char write_buf[32]="hello world";
//可读可写方式创建,若文件存在则覆盖
if((fd=open("example_63.c",O_RDWR|O_CREAT|O_TRUNC,S_IRWXU))==-1)//先打开文件,获得文件描述符
my_err("open",__LINE__);
else printf("create file success\n");
//写
if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf))//判断写是否完全成功
my_err("write",__LINE__);
my_read(fd);//再读
printf("/*------------*/\n");
if(lseek(fd,10,SEEK_END)==-1)//往文件末尾再向后移动10字节
my_err("lseek",__LINE__);
if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf))//在文件末尾后10字节处开始再写
my_err("write",__LINE__);
my_read(fd);//读
close(fd);
return 0;
}
运行结果
但是不完全对,运行下面命令发现
具体解释而言
if(lseek(fd,10,SEEK_END)==-1)//往文件末尾再向后移动10字节
my_err("lseek",__LINE__);
文件读写指针移动到EOF后10字节再写,中间的间隔以'\0'填充,但是'\0'在C语言打印为空,所以程序打印的结果和查看文件内容的结果不尽相同。
顺便了解
od
命令是一个用于显示文件内容的 Linux/Unix 命令。它以八进制或十六进制的形式显示文件的内容,也可以按字节、短整数、长整数等格式显示。以下是
od
命令的基本语法:
od [options] [file]
其中,
file
是要查看内容的文件名。一些常用的选项包括:
-a
:以字符和八进制的形式显示文件内容。-t
:指定显示的格式,比如-to2
表示以八进制短整数的形式显示。-x
:以十六进制形式显示文件内容。-c
:以字符形式显示文件内容。
perror
函数是一个用于打印与当前errno
值相关联的错误消息的标准C库函数。它的原型如下:
#include <stdio.h>
void perror(const char *s);
其中:
s
是一个用户自定义的字符串,用于在错误消息前输出一些额外的信息。通常,这个字符串是简短的描述性文字,以帮助理解错误的上下文。
perror
函数的作用是将errno
的当前值转换为对应的错误消息,并将该消息输出到标准错误流(stderr)。perror
在输出错误消息后,会加上冒号和空格,然后输出s
指定的字符串,最后再输出一个换行符。比如
#include <stdio.h> #include <errno.h> int main() { FILE *file = fopen("nonexistent_file.txt", "r"); if (file == NULL) { perror("Error opening file"); } return 0; }
在上面的例子中,如果
fopen
失败(比如因为文件不存在),perror
将打印类似于以下的消息:
Error opening file: No such file or directory
fprintf(stderr, "line:%d ", line);
这行代码使用了
fprintf
函数来将格式化的输出发送到标准错误流(stderr
)。下面是对该代码片段的解释:
fprintf
函数:
fprintf
是标准C库提供的函数,用于将格式化的数据写入流中。- 它的原型为:
int fprintf(FILE *stream, const char *format, ...);
stream
参数指定要写入的流,可以是stdout
(标准输出)或stderr
(标准错误)等。format
参数是一个字符串,指定了输出的格式,类似于printf
中的格式字符串。- 后续的参数是要插入到格式字符串中的值。
stderr
流:
stderr
是标准错误流,与stdout
(标准输出流)类似,但通常用于输出错误信息。- 在C语言中,
stderr
是一个预定义的文件指针,表示指向标准错误流的指针。- 输出到
stderr
通常用于报告程序运行中的错误和警告,而不是正常的输出。
fprintf(stderr, "line:%d ", line);
会将输出发送到标准错误流 (stderr
),而在命令行中运行程序时,这些错误消息会在命令行终端上显示。在Linux或Unix系统中,标准输出 (
stdout
) 通常与命令行终端关联,而标准错误 (stderr
) 也会显示在相同的终端上。这意味着通过fprintf(stderr, ...)
输出的内容将显示在运行程序的命令行终端上,而不是被重定向到文件或其他位置。