文件读写(C++)

  文件操作与内存分配一样,是在程序中频繁使用的操作。包括文件的创建、打开、读写、关闭等。

下面总结C语言、C++语言、VC、Win32、内核的文件操作:

  需要特别指出的是,在读写文件时,文件中的换行标志在Windows中为"\r\n",而在Linux等系统中, 为"\n"。

C语言文件访问:

1)标准C方式:

FILE *fp;
//打开
fp = fopen("path\to\file","rwt");

//文件读写
fread(buffer, size, ntime, fp);
fwrite(buffer, size, ntime, fp);

//格式化输入/输出
fscanf(fp,"%s,...", String1, ...);
fprintf(fp, "%d,..", a, ..);

//字符输入/输出
fgetc(fp);
fputc(c,fp);

//字符串输入/输出
fgets(name[], maxsize, fp);
fputs(name, fp);

//调整读写的指针
rewind(fp);
fseek(fp, 50, 0/1/2);

//关闭文件句柄
fclose(fp);

//判断文件是否结束
feof(pf);

在打开文件时候,需要设置打开文件的标志。一些常见的标志见下表:

标志 含义
r 读模式,如果文件不存在则会失败
w 写模式,如果文件存在则会清空其内容
a  追加模式,写入的内容追加在原有内容之后,如果文件不存在则会自动创建
r+ 读/写模式,文件必须存在
a+ 读+追加模式
t 文本方式
b 二进制方式
css=ENCODING 文件编码方式,可指定ENCODING为UTF-8, UTF-16LE, UNICODE

eg:关于文件操作的面试题:设计一个程序算法,使其读文件file1.txt中的数据:

    12

    34

    56

按以下顺序输出到file2.txt:

    56

    34

    12

代码如下:

  void reversefile(FILE* fread, FILE* fwrite)

  {

    assert(fread != NULL & fwrite != NULL);

    char buf[1024] = {0};

    if(!fgets(buf, sizeof(buf), fread))

      return;

    reverse(fread,  fwrite);

    fputs(buf, fwrite);

  }

int reveref1tof2(const char * rfile, const char * wfile)

{

  FILE * fr = NULL;

  FILE * fw = NULL;

  fr = fopen(rfile, "rb");

    if(fr == NULL)

      exit(-1);

  fw = fopen(wfile, "wb");

    if(fw == NULL)

      exit(-1);

  reversefile(fr, fw);

  fclose(fr);

  fclose(fw);

  return 0;

}

2) UNIX方式

在UNIX中,文件读写方式如下:

  int fd;

  fd = open("path\to\file", O_CREATE|O_WRONLY|O_RDONLY);

  write(fd, buffer, size);

  read(fd, buffer, &size);

  close(fd);

open与fopen都可以打开和访问一个文件,那么它们的区别是什么呢?

实际上, open是UNIX系统调用如下(图1示),它返回一个文件句柄,fopen是一个C的标准库函数,返回一个文件指针。open不是标准IO库的函数,用open打开的文件读写是不带缓存的,直接读写磁盘数据。fopen是C标准IO库的函数(如图2),用fopen打开的文件读写是带缓存的,即用fwrite向文件里写一个字节,一般来讲它不会立刻调用write将该操作提交给kernel,而是积累到一定程度再一起写。从返回值来看,fopen返回FILE *的指针,这个结构维护着一些关于这个文件的信息,而open返回的是这个被打开的文件的id,这个id是内核来维护的。但fopen返回的FILE结构记录着这个文件的id。

图1示(open()打开方式):

图2示(fopen()打开方式):

C++语言文件访问

在C++中,文件访问方式如下:

ofstream outFile("path\to\file",ios::out);

ifstream inFile("path\to\file", ios::in);

inFile.read(buffer, size);

outFile.wreite(buffer,size);

inFile.close();

outFile.close();

C++对文件的操作如下图求:

VC文件访问

在VC中,文件访问方式如下:

CFile file;

file.Open("path\to\file", CFile::modeCreate|CFile::modeRead|CFile::modeWrite);

file.Read(buffer, size);

file.Write(buffer,size);

file.Close();

Win32文件访问:

在Win32中,文件访问方式如下:

HANDLE hHandle;

DWORD dwError;

hHandle = CreateFile(TEXT("Path\\to\\file"),

          GENERIC_READ|GENERIC_WRITE,

          0, // shareMode

          NULL,

          CREATE_NEW,

          FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,

          NULL);

if(hHandle == INVALID_HANDLE_VALUE)

{

  dwError = GetLastError();

}

BOOL bWrite, bRead;

char buf[100] = "Hello, world";

DWORD n;

bWrite = WriteFile(hHandle, buf, sizeof(buf), &n, 0);

if(bWrite == 0)

{

  dwError = GetLastError();

}

CloseHandle(hHandle);

hHandle = CreateFile(TEXT("Path\\to\\file"),

          GENERIC_READ|GENERIC_WRITE,

          0, //shareMode

          NULL,

          OPEN_EXISTING,

          FILE_ATTRIBUTE_NORMAL,

          NULL);

bRead = ReadFile(hHandle, buf, sizeof(buf), &n, 0);

  if(bRead == 0)

  {

    dwError = GetLastError();

  }

CloseHandle(hHandle);

内核文件访问:

在内核态要访问文件,不能直接调用 上面的方法,而必须调用内核态专门访问文件的函数。

1)Linux内核文件访问方式

struct file * kopen(const char * filename, int flags, int mode)

{

  struct file * f = NULL;

  f = filp_open(filename, flags, mode);

  return f;

}

ssize_t kread(struct file* f1, char *buf, size_t count)

{

  ssize_t ret = 0;

  struct file * file = NULL;

  mm_segment_t fs;

  file = f1;

  if(file)

  {

    ssize_t(*read)(struct file*, char*, size_t, loff_t *);

    fs = get_fs();

    set_fs(KERNEL_DS);

    if(file->f_op && (read=file->f_op->read) != NULL)

      red = read(file,buf,count,&file->f_pos);

    set_fs(fs);

  }

  return ret;

}

ssize_t kwrite(struct file* f1, const char * buf, size_t count)

{

  ssize_t ret;

  struct file * file;

  mm_segment_t fs;

  file = f1;

  if(file)

  {

    ssize_t(*write)(struct file*, const char*, size_t, loff_t*);

    fs=get_fs();

    set_fs(KERNEL_DS);

    if(file->f_op && (write=file->f_op->write) != NULL)

      ret = write(file, buf, count, &file->f_pos);

    set_fs(fs);

  }

  return ret;

}

2)Windows内核文件访问方式:

Windows内核文件访问方式如下:

NTSTATUS KOpen(const WCHAR* filename, HANDLE &h)

{

  UNICODE_STRING uFile;

  OBJECT_ATTRIBUTES objAttrib;

  NTSTATUS status;

  RtlInitUnicodeString(&uFile, filename);

  InitializeObjectAttributes(&objAttrib,

    &uFile,

    OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,

    NULL,

    NULL);

  status = ZwCreateFile(

    &h,

    FILE_READ_DATA|FILE_READ_ATTRIBUTES,

    &objAttrib,

    &io_status,

    NULL,

    FILE_ATTRIBUTE_NORMAL,

    FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,

    FILE_OPEN,

    FILE_SYNCHRONOUS_IO_NONALERT,

    NULL,

    0);

  return status;

}

NTSTATUS KRead(HANDLE h, PVOID buff, ULONG * len)

{

  LARGE_INTEGER offset ={0};

  IO_STATUS_BLOCK io_status={0};

  NTSTATUS status;

  status = ZwReadFile(

    h,NULL, NULL,NULL,

    &io_status, buffer, *len, &offset,

    NULL);

    *len = (ULONG)io_status.Information;

   return status;

}

NTSTATUS KWrite(HANDLE h, PVOID buff, ULONG len)

{

  LARGE_INTEGER offset ={0};

  IO_STATUS_BLOCK io_status ={0};

  NTSTATUS status;

 

  status = ZwWriteFile(

    h,NULL, NULL, NULL,

    &io_status,buffer, len,offset,

    NULL);

  offset.QuadPart += len;

  return status;

}

 

  

 

 

 

posted @ 2018-09-17 00:05  cindy_zl  阅读(1009)  评论(0编辑  收藏  举报