常用的文件IO操作



学习内容:

    1)open函数的flag

  2)linux系统如何管理文件

  3)lseek详解

  4)dup和dup2函数介绍

  5)标准IO库介绍



如何查man手册:man 1 xx查linux shell命令,man 2 xxx查API, man 3 xxx查库函数

1、open函数的flag

  大家有没有发现open函数有两个如下,

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

多了一个mode,查看man手册可以发现作用为O_CREAT创建了新文件时对文件的权限设置,如下图:

常用的flag:

  1)读写权限:O_RDONLY(只读), O_WRONLY(只写), O_RDWR(可读可写).

  2)打开存在并有内容的文件时:O_APPEND(追加)、O_TRUNC(覆盖)

  3)打开不存在的文件时:O_CREAT(覆盖创建)、O_EXCL(确保文件创建) O_EXCL标志和O_CREAT标志来结合使用,没有文件时创建文件,有这个文件时会报错提醒我们。

  4)阻塞与非阻塞:O_NONBLOCK(非阻塞)我们打开一个文件默认就是阻塞式的,如果你希望以非阻塞的方式打开文件,则flag中要加O_NONBLOCK标志,只用于设备文件,而不用于普通文件。

  5)write非阻塞等待:O_SYNC  无O_SYNC时write只是将内容写入底层缓冲区即可返回,在合适的时候会将buf中的内容一次性的同步到硬盘中。这种设计是为了提升硬件操作的性能和销量,提升硬件寿命;但是有时候我们希望硬件不好等待,直接将我们的内容写入硬盘中,这时候就可以用O_SYNC标志。

2、linux系统如何管理文件

  1)硬盘中的静态文件和inode(i节点)

  硬盘中可以分为两大区域:一个是硬盘内容管理表项,另一个是真正存储内容的区域。操作系统访问硬盘时是先去读取硬盘内容管理表,从中找到我们要访问的那个文件的扇区级别的信息,然后再用这个信息去查询真正存储内容的区域,最后得到我们要的文件。而这个管理表中以文件为单位记录了各个文件的各种信息,每一个文件有一个信息列表(我们叫inode,i节点,其实质是一个结构体,这个结构体有很多元素,每个元素记录了这个文件的一些信息,其中就包括文件名、文件在硬盘上对应的扇区号、块号那些东西·····)

实用:大家格式化硬盘(U盘)时发现有:快速格式化和底层格式化。快速格式化非常快,格式化一个32GB的U盘只要1秒钟,普通格式化格式化速度慢。这两个的差异?其实快速格式化就是只删除了U盘中的硬盘内容管理表(其实就是inode),真正存储的内容没有动。这种格式化的内容是有可能被找回的。

  2)内存中被打开的文件和vnode(v节点)

  一个程序的运行就是一个进程,我们在程序中打开的文件就属于某个进程。每个进程都有一个数据结构用来记录这个进程的所有信息(叫进程信息表),表中有一个指针会指向一个文件管理表,文件管理表中记录了当前进程打开的所有文件及其相关信息。文件管理表中用来索引各个打开的文件的index就是文件描述符fd,我们最终找到的就是一个已经被打开的文件的管理结构体vnode。

3、lseek详解

off_t lseek(int fd, off_t offset, int whence);

whence就是代表一个参考位置(用来表示文件开始处到文件当前位置的字节数)offset代表一个偏移量

参数 offset 的含义取决于参数 whence:

SEEK_SET,则返回的文件偏移量将被设置为 offset。

SEEK_CUR,则返回的文件偏移量将被设置为 cfo 加上 offset,

SEEK_END,则返回的文件偏移量将被设置为文件长度加上 offset,

  1)文件指针:当我们要对一个文件进行读写时,一定需要先打开这个文件,所以我们读写的所有文件都是动态文件。动态文件在内存中的形态就是文件流的形式。

  2)在动态文件中,我们会通过文件指针来表征这个正在操作的位置。所谓文件指针,就是我们文件管理表这个结构体里面的一个指针如上图。所以文件指针其实是vnode中的一个元素。这个指针表示当前我们正在操作文件流的哪个位置。这个指针不能被直接访问,linux系统用lseek函数来访问这个文件指针。

  3)read和write函数都是从当前文件指针处开始操作的,所以当我们用lseek显式的将文件指针移动后,那么再去read/write时就是从移动过后的位置开始的。

  4)用lseek计算文件长度

eg:return=lseek(fd,0,SEEK_END);//表示从文件末尾

  5)用lseek构建空洞文件,这个文件中有一段是空的

  6)使用实列:

首先我们看到a.txt里面全都是f,其实我们用O_APPEND就可以在后面追加内容,而我们用lseek来随意位置追加内容

使用SEEK_END

lseek(fd,0,SEEK_END);//在write1前使用一次和O_APPEND同等效果,在write之后再使用一次即可的读取出当前文件的长度

4、dup和dup2函数介绍

int dup(int oldfd);
int dup2(int oldfd, int newfd);//返回值即为newfd

  1) 什么是文件共享:同一个文件(同一个文件指的是同一个inode,同一个pathname)被多个独立的读写体(几乎可以理解为多个文件描述符)去同时(一个打开尚未关闭的同时另一个去操作)操作。

  2) 进行文件描述符复制:dup并不能指定分配的新的文件描述符的数字,dup2系统调用修复了这个缺陷。dup返回的fd和原来的oldfd都指向oldfd打开的那个【动态文件】,操作这两个fd实际操作的都是oldfd打开的那个文件。实际上构成了文件共享

  3) fd小于3的分别对应于,stdin(0)、stdout(1)、stderr(3),也就是标准输入、标准输出、标准错误。

  4)实现标准输出的重定位实例

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#define FILEPATH    "a.txt"
int main(int argc,char *argv[])
{
    int fd=-1;
    int i=-1; //实际向文件中写入的字节数
    int j=-1;//实际向文件中写入的字节数
    int k;//用dup复制后的文件描述符

    char b[100]= "bbbbbadfghgdfh";
  //打开一个文件操作
    fd=open(FILEPATH, O_RDWR );
    if(-1==fd)
    {
        printf("文件打开失败!\n");
        perror("open:");
        return 0;
    }
    else
    {
        printf("文件打开成功!fd=%d\n",fd);
    }
    close(1);   //关闭标准输出文件描述符1
    k=dup(fd);  //实现重定位
    j=write(k,&b,20);
    if(-1==j)
    {
        printf("写入文件失败\n");
        perror("写入");
        return 0;
    }
    printf("write succeed!\n");
    close(fd);
    return 0;
}

5、标准IO库介绍

  1)标准IO和文件IO有什么区别:标准IO是C库函数(也是通过调用API来完成操作的),而文件IO是linux系统的API(API类似于一种接口,是由操作系统提供的)

  2)常用标准IO函数介绍:fopen、fclose、fwrite、fread、ffulsh(刷新标准库函数的缓存,直接写进操作系统的缓冲区中)、fseek

  3)一个简单的标准IO读写文件实例

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>

#define FILEPATH    "a.txt"

int  main(int argc,char *argv[])
{
    FILE *fd = NULL;  //定义一个文件指针
    int ret = 0;
    char Wrtebuff[10]={"sdfgdjdytr"};
    fd=fopen(FILEPATH, "r+");
    if(NULL == fd)
    {
        printf("文件打开失败!\n");
        perror("open");
        return 0;
    }
    ret = fwrite(Wrtebuff,1,sizeof(Wrtebuff),fd);
    if(ret<0)
    {
        perror("write");
        return 0;
    }
    printf("文件写入成功!\n");

    return 0;
}

原文地址:https://www.cnblogs.com/ncne/p/10987690.html

时间: 2024-10-18 04:37:51

常用的文件IO操作的相关文章

imx6用文件io操作gpio

具体请参考: http://blog.csdn.net/u014213012/article/details/53140781 这里要注意的是: 要让linux支持文件io方式操作gpio,首先驱动必须得支持,也就是说设备树上必须先配置好gpio模式,然后参照以上链接去实现gpio操作 这里举例来说:hud项目中(imx6dl平台),有一个蓝牙电源的使能受GPIO1_IO30的控制,所以我们必须得在设备树上配置这个pad为GPIO模式 1.配置gpio模式 现在需要在设备树上配置GPIO1_IO

Linux学习记录--文件IO操作相关系统编程

文件IO操作相关系统编程 这里主要说两套IO操作接口,分别是: POSIX标准 read|write接口,函数定义在#include<unistd.h> ISO C标准 fread|fwrite接口,函数定义在#include<stdio.h> 有书上说POSIX标准与ISO C标准的区别在于文件读写是否带缓冲区,我则不是很认同,因此POSIX标准下的IO操作也是带缓冲区的,至于这两个标准下的IO性能谁更加好则不一定,因为这和缓冲区的大小,以及用户逻辑有很大关系. POSIX标准

文件IO操作

前言 本文介绍使用java进行简单的文件IO操作. 操作步骤 - 读文件 1. 定义一个Scanner对象 2. 调用该对象的input函数族进行文件读取 (参见下面代码) 3. 关闭输入流 说明:其实和标准输入没什么不同.唯一要注意的区别就是 1 中Scanner构造函数的参数要是路径类型那么才是读文件,否则就是读字符串.(参考下面代码注释部分) 示例代码 1 package test; 2 3 import java.io.IOException; 4 import java.nio.fil

树莓派学习笔记——使用文件IO操作GPIO SysFs方式

0 前言 本文描述如果通过文件IO sysfs方式控制树莓派 GPIO端口.通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction和value等,direction控制GPIO方向,而value可控制GPIO输出或获得GPIO输入. Linux学习可从应用出发,先不纠结Linux驱动编写,先把Linux给玩起来. [相同与不同] 本文和[EasyARM

【UNIX环境高级编程】文件 IO 操作 - 基础函数 open close creat lseek write read 详解

博客地址 : http://blog.csdn.net/shulianghan/article/details/46980271 一. 文件打开关闭操作相关函数介绍 1. open 函数 (1) open 函数简介 open 函数解析 : -- 函数定义 : #include <fcntl.h> int open(const char *path, int oflag, ...); -- 函数作用 : 打开或者创建一个文件; -- 返回值 : 打开文件成功, 返回文件描述符; 如果失败, 返回

标准文件IO详解(一)---文件IO操作和标准文件IO操作的区别

POSIX IO操作称为文件IO,也称为低级文件IO,是操作系统提供的系统调用,属于没有缓冲区的文件操作方式.执行该种操作后,内容会直接被写入到内核中的提供给磁盘的专门缓冲区中,内核会定期的刷新该缓冲区,将内容同步到磁盘当中. ANSI  C IO操作称为标准文件IO,也称为高级文件IO,是C库函数提供的,属于带有缓冲区的文件操作方式.执行该种操作后,内容首先会将内容写入到用户空间的缓冲区中,待缓冲区满或者需要刷新的时候再去调用文件IO,将内容写入到内核的磁盘缓冲区当中. 相比于低级文件IO,高

Java文件IO操作应该抛弃File拥抱Path和Files

Java7中文件IO发生了很大的变化,专门引入了很多新的类: import java.nio.file.DirectoryStream;import java.nio.file.FileSystem;import java.nio.file.FileSystems;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.nio.file.attribute.FileAt

Python常用的文件读写操作和字符串操作

文件读写操作 fileUtils.py # -*- coding: utf-8 -*- import os def getFileList(dir, fileList=[]):     """     遍历一个目录,输出所有文件名     param dir: 待遍历的文件夹     param filrList : 保存文件名的列表     return fileList: 文件名列表     """     newDir = dir     

java常用的文件读写操作

现在算算已经做java开发两年了,回过头想想还真是挺不容易的,java的东西是比较复杂但是如果基础功扎实的话能力的提升就很快,这次特别整理了点有关文件操作的常用代码和大家分享 1.文件的读取(普通方式) (1)第一种方法 [java] view plain copy File f=new File("d:"+File.separator+"test.txt"); InputStream in=new FileInputStream(f); byte[] b=new