C语言文件操作

一 缓冲文件系统

  缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执行读文件的操作时,从磁盘文件将数据先读入内存缓冲区”,装满后再从内存“缓冲区”依此读入接收的变量。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存 “缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。

二 非缓冲文件系统

  非缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数 据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度 快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar 等。

三 fopen与open的区别

  open是标准c函数。返回文件流而不是linux下文件句柄,设备文件不可以当成流式文件来用,只能用open。一般用fopen打开普通文件,用open打开设备文件。
  fopen和open最主要的区别是fopen在用户态下就有了缓存,在进行read和write的时候减少了用户态和内核态的切换,而open则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列快;如果随机访问文件open要比fopen快。fopen使用了FILE这个结构才保存缓冲数据。open没有缓存机制,每次读操作都直接从文件系统中获取数据,FILE这个结构的定义,FILE包含了一个open返回回来的handle。
  前者属于低级IO,后者是高级IO。open是系统调用,返回的是文件句柄,文件的句柄是文件在文件描述副表里的索引,fopen是ANSIC标准中的C的库函数,在不同的系统中应该调用不同的内核api,返回的是一个指向文件结构的指针。后者是在前者的基础上扩充而来的,在大多数情况下,用后者。fopen可移植,open不能。

四 stat()和fstat()函数

头文件:

#include <sys/stat.h>
#include <unistd.h>

定义函数:int stat(const char * file_name, struct stat *buf);
函数说明:stat()用来将参数file_name 所指的文件状态, 复制到参数buf所指的结构体stat中。
定义函数:int fstat(int fildes, struct stat *buf);
函数说明:fstat()用来将参数fildes 所指的文件状态, 复制到参数buf 所指的结构中(struct stat). Fstat()与stat()作用完全相同, 不同处在于传入的参数为已打开的文件描述词,详细内容请参考stat()。
返回值:执行成功则返回0,失败返回-1,错误代码存于errno
错误代码:

ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长

struct stat {
    dev_t         st_dev;       //文件的设备编号
    ino_t         st_ino;       //节点
    mode_t        st_mode;      //文件的类型和存取的权限
    nlink_t       st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t         st_uid;       //用户ID
    gid_t         st_gid;       //组ID
    dev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号
    off_t         st_size;      //文件字节数(文件大小)
    unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)
    unsigned long st_blocks;    //块数
    time_t        st_atime;     //最后一次访问时间
    time_t        st_mtime;     //最后一次修改时间
    time_t        st_ctime;     //最后一次改变时间(指属性)
};

  先前所描述的st_mode 则定义了下列数种情况:

S_IFMT   0170000    文件类型的位遮罩
S_IFSOCK 0140000    scoket
S_IFLNK 0120000     符号连接
S_IFREG 0100000     一般文件
S_IFBLK 0060000     区块装置
S_IFDIR 0040000     目录
S_IFCHR 0020000     字符装置
S_IFIFO 0010000     先进先出
S_ISUID 04000     文件的(set user-id on execution)位
S_ISGID 02000     文件的(set group-id on execution)位
S_ISVTX 01000     文件的sticky位
S_IRUSR(S_IREAD) 00400     文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200     文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100     文件所有者具可执行权限
S_IRGRP 00040             用户组具可读取权限
S_IWGRP 00020             用户组具可写入权限
S_IXGRP 00010             用户组具可执行权限
S_IROTH 00004             其他用户具可读取权限
S_IWOTH 00002             其他用户具可写入权限
S_IXOTH 00001             其他用户具可执行权限

  上述的文件类型在POSIX中定义了检查这些类型的宏定义:

S_ISLNK(st_mode):是否是一个连接.
S_ISREG(st_mode):是否是一个常规文件.
S_ISDIR(st_mode):是否是一个目录
S_ISCHR(st_mode):是否是一个字符设备.
S_ISBLK(st_mode):是否是一个块设备
S_ISFIFO(st_mode):是否 是一个FIFO文件.
S_ISSOCK(st_mode):是否是一个SOCKET文件

  若一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名。

struct statfs {
    long    f_type;          //文件系统类型
    long    f_bsize;         //块大小
    long    f_blocks;        //块多少
    long    f_bfree;         //空闲的块
    long    f_bavail;        //可用块
    long    f_files;         //总文件节点
    long    f_ffree;         //空闲文件节点
    fsid_t f_fsid;           //文件系统id
    long    f_namelen;       //文件名的最大长度
    long    f_spare[6];      //spare for later
};

五 文件读写步骤

  1、创建文件描述符,open()函数;
  2、定义struct stat buf;
  3、获取文件状态,fstat()函数,stat()函数;
  4、读写操作。

六 非阻塞读取

  对于文件的阻塞模式还是非阻塞模式:
  方法1、open时,使用O_NONBLOCK;
  方法2、fcntl设置,使用F_SETFL,flags|O_NONBLOCK;

七 在文件中间添加内容

#include <stdio.h>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
  int fd = open("ttt", O_RDWR);
  if(fd == -1)
  {
     printf("open faild!\n");
  }
  
  struct stat sb;
  fstat(fd, &sb);
  char buff[200] = "\0";
  lseek(fd, 4, SEEK_SET);
  int i = read(fd, buff, sb.st_size - 4);
  cout << buff << endl;   
    
  lseek(fd, 4, SEEK_SET);
  write(fd, "wdxwan!!!", 9);
  write(fd, buff, i);
  read(fd, buff, sb.st_size + 9 + i);
  cout << buff << endl;   
  close(fd);
  return 0;
 } 

八 文件特定内容的替换

#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <sys/stat.h>

#define MAXSIZE 50000

char* substr(const char*str, unsigned long start, unsigned long end);
void replace(const char *path, const char *ori, const char *dst);

int main(int argc, char** argv)
{
   replace(argv[1], " )", ")");
   replace(argv[1], "( ", "(");
   replace(argv[1], "[ ", "[");
   replace(argv[1], " ]", "]");
   replace(argv[1], " }", "}");
   replace(argv[1], "{ ", "{");
   return 0;
}

char* substr(const char*str, unsigned long start, unsigned long end)
{
   unsigned long n = end - start;
   static char stbuf[20];
   strncpy(stbuf, str + start, n);
   stbuf[n] = 0;
   return stbuf;
}

void replace(const char *path, const char *ori, const char *dst)
{
   int fd = open(path, O_RDWR);
   if(fd == -1)
   {
      printf("open file faild!\n");
   }
   struct stat sb;
   fstat(fd, &sb);

   unsigned char *start = (unsigned char *)mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
   if(start == MAP_FAILED)
   {
      printf("映射失败,文件过大或者没有权限");
      return;
   }

   unsigned char buf[MAXSIZE];
   unsigned long i = 0;

   unsigned long dSize = sb.st_size;

   unsigned char buffer2[MAXSIZE];
   memccpy(buffer2, start, sizeof(unsigned char), sb.st_size);

   while (i < dSize)
   {
      if(0 == strcmp(ori, substr((char *)buffer2, i, i + strlen(ori))))
      {
         lseek(fd, i + strlen(ori), SEEK_SET);
         int m = read(fd, buf, dSize - i - strlen(ori));

         lseek(fd, i + strlen(dst), SEEK_SET);
         ftruncate(fd, i + strlen(ori));
         write(fd, buf, m);

         lseek(fd, i, SEEK_SET);
         write(fd, dst, strlen(dst));

         dSize = dSize - strlen(ori) + strlen(dst);
         lseek(fd, 0, SEEK_SET);
         memset(buffer2, 0, MAXSIZE);
         read(fd, buffer2, dSize);

      }
      ++i;
   }
   close(fd);
   munmap(start, sb.st_size); /* 解除映射 */
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值