Linux 文件操作 小白

ssh远程链接不上虚拟机解决方案

ifdwn eth0 //关闭网络

ifup eth0 //启动网络 //如果还不行

虚拟机先关闭linux-编辑-虚拟网络编辑器-更改设置-还原默认设置

注 设置完成之后地址可能会发生变化

ps -ef grep 程序名 //输出这个程序的信息程序名写一半就是同名这一半的所有信息(当前运行的程序) 获取当前程序的进程id

ps -ef //打印所有的进程信息 UID //进程的ID PPID 父进程的id

进入那个正在执行的程序的fd cd /proc/进程id/fd //就可以查看0表示标准输入(键盘),1表示标准输出(控制台),2表示标准错误 (控制台)

printf 另一种写法 write(1,"I love you",长度) ;写道标准输出

文件操作

#include<unistd.h>

*write*//写文件

ssize_t write(int fd, const void *buf, size_t count);

第一个参数 写到文件描述句柄中(句柄)
第二个参数文件数据类型 ,
第三个参数是大小 成功返回字节数 失败返回-1错误编号设置 errno 可用( strerror(errno) ) 查看

注意:是从文件的当前指针位置写入!//刚打开时文件指针在文件头部

*read读文件*

ssize_t read(int fd, const void *buf, size_t count);

第一个参数从文件描述句柄中读,
第二个参数读到哪个位置,
第三个读的字节数

返回值 出错返回-1错误编号设置 errno 可用( strerror(errno) ) 查看,返回读到的字节数 0表示读到文件的末尾

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    
    
   char buffer[1024];
  int cnt = 0;//从标准输入中读取
  cnt = read(0, buffer, sizeof(buffer));
  write(1, buffer, cnt);//1表示标准输出(控制台)
  return 0;
}

./程序名 < main.c /* 利用重定向, 使用文件main.c作为输入 < 表示重定项
./程序名 < main.c /* > 符号 表示往main.c 中写 在控制台输入之后不会显示到控制台 会直接写道 main.c中去*/

*open*

​ (1) 用法

   #include <stdio.h>
   #include<unistd.h>
   #include <stdlib.h>



//open头文件
   #include <sys/types.h>
   #include <sys/stat.h>
   #include <fcntl.h>


   int open(const char *pathname, int flags);//路径打开方式   | 符号可用多个方式打开  默认是读写   如果加第3个参数 那么表示权限

​    (2) 返回值

​       成功:文件描述符

​       失败:-1

​    (3) 打开方式

​       O_RDONLY     只读

​       O_WRONLY     只写

​       O_RDWR      读写

​        O_CREAT      如果文件不存在,则创建该文件,并使用第3个 

参数设置权限,如果文件存在 ,则只打开文件

 

​       O_EXCL       如果同时使用O_CREAT而且该文件又已经存在

时,则返回错误, 用途:以防止多个进程同时创建//如果存在就打开失败

 O_APPEND     尾部追加方式(打开后,文件指针指向文件的末尾)

​       O_TRUNC      若文件存在,则长度被截为0,属性不变

​		example:  open("/dev/hello", O_RDONLY|O_CREAT|O_EXCL, 0777)        

​    (4) 参数3 (设置权限)

​       当使用O_CREAT时,使用参数3

​          

​       S_I(R/W/X)(USR/GRP/OTH)//详情 man 2 open

​       例:

​        S_IRUSR | S_IWUSR   文件的所有者对该文件可读可写

​        (八进制表示法)0600   文件的所有者对该文件可读可写

 

​			

​			

​    注意:

​       返回的文件描述符是该进程未打开的最小的文件描述符

*****\*close\******

close (int 文件句柄);

终止指定文件描述符与对应文件之间的关联, 并释放该文件描述符,即该文件描述符可被重新使用

返回值

​        成功: 0

​        失败: -1

***\*lseek\*//重新定义文件读和写的位置***

```c++
#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
1文件句柄

2 偏移量多少位置

3相对哪里偏移 枚举参详 man lseek





返回值

​       成功:返回新的文件位置与文件头之间偏移

​       失败: -1

标准I/O库

//这些函数带缓冲功能,在执行系统调用时可以避免不必要的开销

 /* C语言中的文件操作中已描述 */

  1)  fwrite   //带缓冲的写,避免多次系统调用,可以提高效率

  2) fread

  3) fopen

  4) fclose

  5) fseek   

  6) fflush

//应用层和内存形成的读写被称为逻辑IO

//内存和物理内存形成的读写被称为物理IO(文件系统调用 “系统调用”)

标准IO

 O_SYNC(open的时候加上)只对写数据有效,(利用写一点就同步的方式    直到写成功才返回)
 它将写入内核缓冲区的数据立即写入磁盘,将机器故障时, 
 数据的丢失减少到最小,但是它仍然要经过内核缓冲区。(效率不高)

标准IO 缓存同步

-为了保证磁盘系统与缓冲区中内容一致,
Linux 系统提供了 sync、fsync 和fdatasync 三个函数.
向打开的文件写数据;  成功返回0 ,若出错,返回-1。
#include <unistd.h>
       int fsync(int fd);
       int fdatasync(int fd);
       void sync(void)//这些函数是缓存同步,也就是说不O_SYNC那样写一点就缓存
       //一点而是按照特定的算法 或者规定写一大块在进行缓存

sync - 将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。这种方式不保证能完全写入到磁盘

fsync - 将fd对应文件的块缓冲区立即写入磁盘,并等待实际写磁盘操作结束返回。//这种方式保证数据成功写入到磁盘

fdatasync - 类似fsync,但只影响文件的数据部分。而除数据外,fsync 还会同步更新文件属性。//更加精确只针对文件的数据部分写入到磁盘


Linux中分为 标准IO和直接IO(不常用) 像 write等都属于标准IO

在这里插入图片描述

open +O_DIRECT = 绕过内核缓冲区的直接访问,便有效避免了CPU和内存的多余时间开销。
注意:直接I/O的缺点就是如果访问的数据不在应用程序缓存中,
那么每次数据都会直接从磁盘进行加载,这种直接加载会非常缓慢!
通常直接I/O跟异步I/O结合使用会得到较好的性能。
直接IO需 加#define _GNU_SOURCE   因为磁盘是扇区的,
不管是读写  必须是512个字节磁盘的特性 需malloc一个512的char数组 
但这个数组的地址又必须要去是512的整数倍所以用另一个函数
posix_memalign(void**)&定义的char指针,512,512)
//生成一个地址是512整数倍的512个字节的空间
 第3个参数是分配的空间 头文件stdlib.h  返回值成功返回0 失败返回非0 错误设置error
 (主要要求必须是内存边界对齐,基于硬件开发,效率较低)
 //读的时候文件大小也必须是512的整数倍

在这里插入图片描述

*proc文件系统*进程文件系统

 /proc是一个特殊的文件系统,

  该目录下文件用来表示与启动、内核相关的特殊信息

  

  1) /proc/cpuinfo

​    CPU详细信息

​    

  2) /proc/meminfo

​    内存相关信息

  

  3) /proc/version

​    版本信息

  

  4) /proc/sys/fs/file-max

 系统中能同时打开的文件总数

​    可修改该文件

  

  5) 进程的相关信息

​    /proc/32689/ 表示指定进程(进程号为32689)的相关信息

​    

  6) cat /proc/devices

​    已分配的字符设备、块设备的设备号

*文件锁*

 #include <unistd.h>
 #include <fcntl.h>

 int fcntl(int fd, int cmd, ... /* arg */ );

查看帮助 man 2 fcntl

struct flock //结构体
{
    
    

  short l_type; /*F_RDLCK 读上锁, F_WRLCK/ 写上锁, or F_UNLCK解锁 */ 

  off_t l_start; /*offset in bytes, relative to l_whence  相对于l_where的偏移量(字节) */

  short l_whence; /*SEEK_SET起始位置, SEEK_CUR, or SEEK_END */

  off_t l_len;  /*length, in bytes长度锁多长的字节; 0 means lock to EOF 表示锁到文件的结尾*/

  pid_t l_pid;  /*returned with F_GETLK进程id */

}

l_type: 第一个成员是加锁的类型:只读锁,读写锁,或是解锁。

l_start和l_whence: 用来指明加锁部分的开始位置。

l_len: 是加锁的长度。

l_pid: 是加锁进程的进程id。

注 当两个进程都是读锁的时候,都可以成功
如果是 一读一写就会出问题,会被阻塞在当前位置
如果是 一写一读就会出问题,会被阻塞在当前位置
如果两个都是写锁那么也会被阻塞

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define FILE_NAME 	"test.txt"
	   
int flock_set(int fd, int type)
{
    
    
	printf("pid=%d into...\n", getpid());//	获取当前进程的id
	//初始化这个结构体
	struct flock flock;
    memset(&flock,0,sizeof(struct flock));
	

	fcntl(fd, F_GETLK, &flock);//查看文件是否有锁

	if (flock.l_type != F_UNLCK) //判断该文件是否有所
    {
    
    
		if (flock.l_type == F_RDLCK) //如果文件有读上锁
        {
    
    
			printf("flock has been set to read lock by %d\n", flock.l_pid);
		} 
        else if (flock.l_type == F_WRLCK) //如果文件有写上锁
        {
    
    
			printf("flock has been set to write lock by %d\n", flock.l_pid);
		}
	}

	flock.l_type = type;//加锁方式
	flock.l_whence = SEEK_SET;//起始位置
	flock.l_start = 0;//相对起始位置偏移量
	flock.l_len = 0;  //锁整个文件 
	flock.l_pid = -1;//p id不需要设置
	if (fcntl(fd, F_SETLKW, &flock) < 0)//F_SETLKW加锁
// 参数2  cmd 命令   F_GETLK、F_SETLK和F_SETLKW 获取锁 设置锁  同步设置锁
//对于存在的记录锁(也称为文件段或文件)
//地区锁)。第三个参数lock是一个指向结构的指针
//它至少有以下字段(未指定顺序)。
    {
    
    
		printf("set lock failed!\n");//加锁失败
		return -1;
	}	

	switch (flock.l_type) //获取设置的加锁的方式
    {
    
    
	case F_RDLCK:
		printf("read lock is set by %d\n", getpid());//打印出当前进程的id//读上锁
		break;
	case F_WRLCK:
		printf("write lock is set by %d\n", getpid());//写上锁
		break;
	case F_UNLCK:
		printf("lock is released by %d\n", getpid());//解锁
		break;
	default:
		break;
	}

	printf("pid=%d out.\n", getpid());
	return 0;
}

int main(void)
{
    
    
	int fd;

	fd = open(FILE_NAME, O_RDWR|O_CREAT, 0666);//0666表示所有权限
	if (fd < 0) {
    
    
		printf("open file %s failed!\n", FILE_NAME);
	}
    
	//flock_set(fd, F_WRLCK);//写上锁   这里F_WRLCK不是cmd 这里是结构体的第一个参数
	flock_set(fd, F_RDLCK);//读上锁
	getchar();
	flock_set(fd, F_UNLCK);//解锁
	getchar();

	close(fd);
	return 0;
}

inode - “索引节点 返回文件的状态信息加粗样式”,

储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。每个inode都有一个号码,操作系统用inode号码来识别不同的文件。ls -i 查看inode 号
``
stat函数
作用:返回文件的状态信息

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

   int stat(const char *path, struct stat *buf);
   int fstat(int fd, struct stat *buf);
   int lstat(const char *path, struct stat *buf);

path:
文件的路径
buf:
传入的保存文件状态的指针,用于保存文件的状态
返回值:
成功返回0,失败返回-1,设置errno

struct stat {
    
    
               dev_t     st_dev;     /* ID of device containing file//设备ID */
               ino_t     st_ino;     /* inode number //inode 编号*/
               mode_t    st_mode;    /* 表示 S_ISREG(st_mode) 这个函数返回真 是一个普通文件  ,S_ISDIR(st_mode) 这个函数返回真是一个目录*/
               
               nlink_t   st_nlink;   /* number of hard links//硬链接的数量 */
               uid_t     st_uid;     /* user ID of owner//用户id*/
               gid_t     st_gid;     /* group ID of owner  //文件的组*/
               dev_t     st_rdev;    /* device ID (if special file) //设备id*/
               off_t     st_size;    /* total size, in bytes //文件的总大小*/
               blksize_t st_blksize; /* blocksize for filesystem I/O//文件占的块的大小 */
               blkcnt_t  st_blocks;  /* number of 512B blocks allocated //文件占的块的数量*/
               time_t    st_atime;   /* time of last access //文件最近访问时间 */
               time_t    st_mtime;   /* time of last modification //上次被修改的时间*/
               time_t    st_ctime;   /* time of last status change //最近状态改变的时间*/
           };

猜你喜欢

转载自blog.csdn.net/qq_45743563/article/details/109486813