zoukankan      html  css  js  c++  java
  • 用Linux系统调用和C语言库函数 两种方式实现文件拷贝(linux程序的IO操作)

    本文的编写主要是在了解,Linux系统调用和C语言库函数的基础上进行的编写代码。

    这篇文章将讲解Linux以下的系统调用:open()、read()、write()、close()、lseek()。涉及到的c语言库函数:fopen()、fread()、fwrite()、fclose()、flseek()。

    用Linux系统调用和C语言库函数 两种方式实现文件拷贝

    采用Linux系统调用实现文件拷贝

      1.open()

    用open函数可以打开或创建一个文件

    1 #include <sys/types.h> 
    2 #include <sys/stat.h> 
    3 #include <fcntl.h>
    4 int open(const char *pathname , int oflag,.../*, mode_t mode * / ) ;
    5 
    6 // 返回:若成功为文件描述符,若出错为- 1
    open()

    pathname 是要打开或创建的文件的名字。oflag参数可用来说明此函数的多个选择项。用下列一个或多个常数进行或运算构成oflag参数(这些常数定义在<fcntl.h>头文件中):
    •O_RDONLY 只读打开。
    •O_WRONLY 只写打开。
    •O_RDWR   读、写打开。
    在这三个常数中应当只指定一个。下列常数则是可选择的:
    •O_APPEND       每次写时都加到文件的尾端。
    •O_CREAT          若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位。
    •O_EXCL            如果同时指定了O_CREAT,而文件已经存在,则出错。这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作。
    •O_TRUNC         如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。
    •O_NOCTTY       如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端。
    •O_NONBLOCK 如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。
    •O_SYNC           使每次write都等到物理I/O操作完成。

      2.read()

    用read函数从打开文件中读数据。

    #include <unistd.h>
    ssize_t read(int filedes, void *buff, size_t nbytes) ;
    
    //返回:读到的字节数,若已到文件尾为0,若出错为-1
    read()

    如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。
    有多种情况可使实际读到的字节数少于要求读字节数:
    • 读普通文件时,在读到要求字节数之前已到达了文件尾端。例如,若在到达文件尾端之前还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将返回0(文件尾端)。
    • 当从终端设备读时,通常一次最多读一行(第11章将介绍如何改变这一点)。
    • 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
    • 某些面向记录的设备,例如磁带,一次最多返回一个记录。
    读操作从文件的当前位移量处开始,在成功返回之前,该位移量增加实际读得的字节数。

       3.write()

    用write函数向打开文件写数据

    1 #include <unistd.h> 
    2 ssize_t write(int f i l e d e s, const void * buff, size_t nbytes) ;
    3 
    4 //返回:若成功为已写的字节数,若出错为- 1
    write

    其返回值通常与参数nbytes的值不同,否则表示出错。write出错的一个常见原因是:磁盘已写满,或者超过了对一个给定进程的文件长度限制。
    对于普通文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了O_APPEND选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。

      4.close()

    可用close函数关闭一个打开文件:

    1 #include <unistd.h> 
    2 int close (int filedes);
    3 
    4 //返回:若成功为0,若出错为-1
    View Code

      5.lseek()

    可以调用lseek显式地定位一个打开文件。

    1 #include <sys/types.h> 
    2 #include <unistd.h> 
    3 off_t lseek(int filedes, off_t offset, int whence) ;
    4 
    5 //返回:若成功为新的文件位移,若出错为- 1
    lseek

    对参数offset的解释与参数whence的值有关。
    •若whence是SEEK_SET,则将该文件的位移量设置为距文件开始处offset个字节。
    •若whence是SEEK_CUR,则将该文件的位移量设置为其当前值加offset,offset可为正或负。
    •若whence是SEEK_END,则将该文件的位移量设置为文件长度加offset,offset可为正或负。

    经过上面的简单学习我们可以采用Linux系统调用实现文件拷贝

     1 #include<stdio.h>
     2 #include<sys/types.h>
     3 #include<sys/stat.h>
     4 #include<fcntl.h>
     5 #include<unistd.h>
     6 #include<stdlib.h>
     7 #include<errno.h>
     8 #include <string.h>
     9 
    10 #define BUFF_SIZE 8192
    11 
    12 int main(int argc,char **argv){
    13     
    14     int from_fd;//源文件的文件描述符
    15     int to_fd;//目标文件的文件描述符
    16     off_t file_size=0;
    17     char buffer[BUFF_SIZE];
    18     int nread;
    19     
    20     //判断参数个数是否正确
    21     if(argc != 3)
    22     {
    23         printf("Usage:%s fromfile tofile
    ",argv[0]);
    24         exit(1);
    25     }
    26     
    27     //打开源文件
    28     if((from_fd=open(argv[1],O_RDONLY))==-1)
    29     {
    30         printf("Open %s Erron
    ",argv[1]);
    31         exit(1);
    32     }
    33     
    34     //创建目标文件
    35     if((to_fd=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR))==-1)
    36     {
    37         printf("Open %s Erron
    ",argv[2]);
    38         exit(1);
    39     }
    40     
    41      //测得文件的大小
    42     file_size=lseek(from_fd,0L,SEEK_END);
    43     lseek(from_fd,0L,SEEK_SET);
    44     printf("from file size is =%ld
    ",file_size);
    45         
    46     //进行文件拷贝
    47     while((nread=read(from_fd,buffer,BUFF_SIZE)) > 0)
    48     {
    49         if((write(to_fd,buffer,nread)) !=nread)   //将buffer中的数据写到目的文件
    50             printf("write error");
    51         bzero(buffer,BUFF_SIZE);
    52     }
    53     close(from_fd);
    54     close(to_fd);    
    55     exit(0);
    56     return 0;
    57 }
    58     
    copy_1

    结果可以用diff命令进行文件的比对

     采用C语言库函数实现文件拷贝

      1.fopen()

    fopen库函数类似于底层的open系统调用。它主要用于文件和终端的输入输出。如果你需要对设备进行明确的控制,那最好使用底层系统调用,因为这可以避免用库函数带来的一些潜在问题,如输入/输出缓冲。

    1 #include <stdio.h> 
    2 FILE *fopen(const char *pathname, const char * type) ;
    3 
    4 //返回:若成功则为文件指针,若出错则为 N U L L
    fopen

    (1)fopen打开路径名由pathname指示的一个文件。
    (2)type参数指定对该I/O流的读、写方式,ANSIC规定type参数可以有15种不同的值

    r 或 r b   为读而打开
    w 或 w b   使文件成为0长,或为写而创建
    a 或 a b  添加;为在文件尾写而打开,或为写而创建
    r+  或 r+b 或 rb+  为读和写而打开
    w+ 或 w+b 或 wb+  使文件为0长,或为读和写而打开
    a+  或 a+b 或 ab+  为在文件尾读和写而打开或创建

      2.fread()、

    fread库函数用于从一个文件流里读取数据。数据从文件流stream读到由ptr指向的数据缓冲区里。fread和 fwrite都是对数据记录进行操作,size参数指定每个数据记录的长度,计数器nitems给出要传输的记录个数。它的返回值是成功读到数据缓冲区里的记录个数(而不是字节数)。当到达文件尾时,它的返回值可能会小于nitems,甚至可以是零。

    1 #include <stdio.h>
    2 size_t fread(void *ptr, size_t size, size_t nitems, FILE * stream) ;
    fread

      3.fwrite()、

    fwrite库函数与fread有相似的接口。它从指定的数据缓冲区里取出数据记录,并把它们写到输出流中。它的返回值是成功写入的记录个数。

    1 #include <stdio .h>
    2 size_ t fwrite(const void *ptr, size_ t size, size_t nitems, FILE * stream) ;
    write

      4.fclose()、

    fclose库函数关闭指定的文件流stream,使所有尚未写出的数据都写出。因为stdio库会对数据进行缓冲,所以使用fclose是很重要的。如果程序需要确保数据已经全部写出,就应该调用fclose函数。虽然当程序正常结束时,会自动对所有还打开的文件流调用fclose函数,但这样做你就没有机会检查由fclose报告的错误了。

    1 #include <stdio.h>
    2 int fclose(FILE * stream) ;
    fclose

      5.flseek()、

    fseek函数是与lseek系统调用对应的文件流函数。它在文件流里为下一次读写操作指定位置。
    offset和whence参数的含义和取值与前面的lseek系统调用完全一样。 但lseek返回的是一个off_t数值,而fseek返回的是一一个整数: 0表示成功,-1表示失败并设置errno指出错误。

    1 #include <stdio.h>
    2 int fseek(FILE *stream, long int offset, int whence) ;
    flseek

    经过上面的简单学习我们可以采用C语言库函数实现文件拷贝

     1 #include<stdio.h>
     2 #include <string.h>
     3 #include<stdlib.h>
     4 
     5 
     6 #define BUFFER_SIZE 1024
     7 
     8 int main(int argc,char **argv)
     9 {
    10     
    11     FILE *from_fd=NULL;
    12     FILE *to_fd=NULL;
    13     int file_size=0;
    14     char buffer[BUFFER_SIZE];
    15     
    16     //判断参数个数是否正确
    17     if(argc != 3)
    18     {
    19         printf("Usage:%s fromfile tofile
    ",argv[0]);
    20         exit(1);
    21     }
    22     
    23     //打开源文件
    24     if(from_fd=fopen(argv[1],"r")==NULL)
    25     {
    26         printf("Open %s Erron
    ",argv[1]);
    27         exit(1);
    28     }
    29     
    30     //创建目标文件
    31     if(to_fd=open(argv[2],"wb+")==NULL)
    32     {
    33         printf("Open %s Erron
    ",argv[2]);
    34         exit(1);
    35     }
    36     
    37     //测得文件大小
    38     fseek(from_fd,0,SEEK_END);
    39     file_size=ftell(from_fd);
    40     printf("the from file size is %d
    ",file_size);
    41     fseek(from_fd,0,SEEK_SET);
    42     
    43     //进行文件的拷贝
    44     while(!feof(from_fd))
    45     {
    46         fread(buffer,BUFFER_SIZE,1,from_fd);
    47         if(BUFFER_SIZE>=file_size)
    48             fwrite(buffer,file_size,1,to_fd);
    49         else
    50         {
    51             fwrite(buffer,BUFFER_SIZE,1,to_fd);
    52             file_size=file_size-BUFFER_SIZE;
    53         }
    54         bzero(buffer,BUFFER_SIZE);    
    55     }
    56     fclose(from_fd);
    57     fclose(to_fd);
    58     exit(0);
    59     return 0;
    60 }
    file_copy

    结果可以用diff命令进行文件的比对

    值得注意的是fseek()不像lseek()会返回读写位置, 因此必须使用ftell()来取得目前读写的位置。

    本文涉及到的关于函数的解释大部分来自《Linux程序设计》

     

  • 相关阅读:
    【leetcode_easy_array】1450. Number of Students Doing Homework at a Given Time
    【leetcode_easy_array】1295. Find Numbers with Even Number of Digits
    【leetcode_easy_array】1266. Minimum Time Visiting All Points
    【leetcode_easy_array】1260. Shift 2D Grid
    【leetcode_easy_array】1275. Find Winner on a Tic Tac Toe Game
    【leetcode_easy_array】1450. Number of Students Doing Homework at a Given Time
    【leetcode_easy_array】1287. Element Appearing More Than 25% In Sorted Array
    【leetcode_easy_array】1299. Replace Elements with Greatest Element on Right Side
    【leetcode_easy_array】1512. Number of Good Pairs
    【leetcode_easy_array】1252. Cells with Odd Values in a Matrix
  • 原文地址:https://www.cnblogs.com/mumu597/p/12662685.html
Copyright © 2011-2022 走看看