文件操作open与fopen和read与fread的区别
来源:互联网 发布:淘宝那些虚拟产品赚钱 编辑:程序博客网 时间:2024/06/17 02:13
系统调用的文件操作分别直接基于IO无缓存操作以及带有缓存操作;
不带缓存的函数特点是直接对文件(包括设备)进行读写操作;
不带缓存的函数不是ANSI C的组成部分,是POSIX的组成部分
都是基于文件描述符,基于基本的IO控制,不带缓存;
关于不带缓存的情景:
运行系统调用时,Linux必须从用户态切换到内核态,执行相应的请求,然后在返回到用户态;
如果不带缓存会频繁的运行系统调用,会降低程序的效率;
标准I/O操作提供流缓存,目的就是尽可能减少使用read()和wirte()等不带缓存的系统调用;
比如:printf(), scanf();
FILE *fdopen(int fd, const char* mode)
FILE *freopen(const char*path, const char*mode, FILE*stream) int close(int fd) int fclose(FILE *stream) ssize_t read(int fd, void *buf, size_t count) size_t fread(void*ptr,size_t size,size_t nmemb,FILE*stream) ssize_t write(int fd, void *buf, size_t count) size_t fwrite(const void*ptr,size_t size,size_t nmemb,FILE*stream) off_t lseek(int fd, off_t offset, int whence) int fseek(FILE *stream, long offset, int fromwhere);
罗列了他们之前的声明,那么该如何选择呢:
使用带缓存操作的特点:
1.存在缓冲,操作外存次数减少,执行速度快效率高
2.fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api
3.fopen是标准c函数。返回文件流而不是linux下文件句柄
4.fopen可移植,open不能
使用直接操作IO:
1.open为系统调用,直接返回文件句柄
2.因为UNIX系统中设备驱动都是文件形式所以推荐使用open进行IO操作
3.设备文件不可以当成流式文件来用,只能用open
标准IO提供了3种类型的带缓冲存储;
1 全缓冲
2 行缓冲
3 无缓冲
自行查找资料了解相关知识点;
一般用fopen打开普通文件,用open打开设备文件
下面分别使用两种方式读取和写入文件:
读取文本中的文件并写入新的文件中(dest_file)
例程来自《嵌入式Linux应用程序开发标准教程》;
//copy_file.c#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#define BUFFER_SIZE 1024// buffer size every read#define SRC_FILE_NAME "copy_file.c"//"src_file" // source file#define DEST_FILE_NAME "dest_file" // copy to this file#define OFFSET 10240 // the lastest dataint main(){ int src_file, dest_file; unsigned char buff[BUFFER_SIZE]; int real_read_len; src_file = open(SRC_FILE_NAME, O_RDONLY); dest_file = open(DEST_FILE_NAME, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (src_file < 0 || dest_file < 0) { printf("Open file error\n"); exit(1); } lseek(src_file, -OFFSET, SEEK_END); while ((real_read_len = read(src_file, buff, sizeof(buff))) > 0) { write(dest_file, buff, real_read_len); } close(dest_file); close(src_file); return 0; }
下面使用带有缓存的fopen进行操作上面的函数:
因为读取非驱动的普通文本文件,所以open和fopen可以互相替代
只是需要修改相关函数参数以及变量即可:
下面只列出修改部分(即main函数)
int main(){ FILE *src_file, *dest_file; unsigned char buff[BUFFER_SIZE]; int real_read_len; src_file = fopen(SRC_FILE_NAME, "r"); dest_file = fopen(DEST_FILE_NAME, "w+"); if (src_file < 0 || dest_file < 0){ printf("Open file error\n"); exit(1); } fseek(src_file, -OFFSET, SEEK_END); while ((real_read_len = fread(buff,1, BUFFER_SIZE, src_file)) > 0) { fwrite(buff, sizeof(char), real_read_len, dest_file); } fclose(dest_file); fclose(src_file); return 0;}
makefile文件:
EXEC = copy_fileOBJS = copy_file.oHEADERS = CC = gccINC = -I.CFLAGS = ${INC} -g all:${EXEC}${EXEC} : ${OBJS} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJS} ${OBJS} : ${HEADERS}.PHONY : cleanclean : -rm -f ${OBJS} ${EXEC}
文件打开后的其他细节方面的操作为:
主要分为3种操作:
fgetc/fputc
getchar/putchar gets/fgets
puts/fputs printf/fprintf/sprintf
vprintf/vfprintf/vsprintf
scanf/fscanf/sscanf int getc(FILE*stream)
int putc(int c,FILE*stream)
int fgetc(FILE*stream)
int fputc(int c,FILE*stream)
int putchar(int ch);
int getchar(void); char*gets(char*str)
int puts(const char*str)
int fputs(const char*s, FILE*stream)
char*fgets(char*s,int size,FILE*stream) int printf(const char*format, …)
int fprintf(FILE*fp,const char*format, …)
int sprintf(char*buf,const char*format, …)
int scanf(const char*format, …)
int fscanf(FILE*fp,const char*format, …)
int sscanf(char*buf,const char*format, …)
字符输入输出测试,分别测试控制台以及本地文件:
1.控制台读写测试:
// test.c#include <stdio.h>main(){ int c; fputc(fgetc(stdin), stdout); //fputc(fgetc(stdin), stdout); //fputc(fgetc(stdin), stdout); fputc('\n',stdout); //putc(getc(stdin), stdout); //putc(getc(stdin), stdout); //putc(getc(stdin), stdout); //putc('\n',stdout); //putchar(getchar()); //putchar(getchar()); //putchar(getchar()); //putchar('\n');}
注释掉的测试代码为:
如果输入字符串在缓存中等待,使用getchar()将会依次读取字符串中的字符出来;
2.本地文件读写测试:
//testfile.c#include<stdio.h>main(){ FILE *filedes; char* DEST_FILE_NAME = "destfile"; filedes = fopen(DEST_FILE_NAME, "w+"); int res = fputs("Hello World\n", filedes); fclose(filedes); filedes = fopen(DEST_FILE_NAME, "r"); if(filedes>0){ puts("------"); int result; while(EOF != (result=fgetc(filedes))){ putc(result, stdout); } fputs("------\n", stdout); }}//运行结果:root@ubuntu:/home/demo/LinuxAPP# gcc testfile.croot@ubuntu:/home/demo/LinuxAPP# ./a.out ------Hello World------root@ubuntu:/home/demo/LinuxAPP#
getc/fgetc/putc/fputc 都是指定流中读写操作
getchar/putchar 是在固定的流(控制台)中读写操作
所以控制台读写本质上读写都是文件;
我们常见的终端输入输出就是一种简单的字符操作:
/* 在Unix系统下,读取键盘输入,向屏幕输入信息. 手动打开键盘和显示器文件并进行读写. */ #include <stdio.h> int main(void) { FILE *pf; pf=fopen("/dev/tty","a+"); //终端字符文件 char sbuf[100]; fprintf(pf, "Please input a string: "); fscanf(pf,"%s",sbuf); fprintf(pf,"The input string is : \"%s\".\n",sbuf); return 0; }
注:/dev/tty为终端字符文件,该文件是对键盘,显示器的抽象,
向该文件写入,则写入内容将被显示在显示器;
读该文件,则将从键盘获得输入;
所以可以看出,其实标准的输入输出是基于流的形式;
也是节约多次调用内核空间的方式;
因为标准输入输出,是非常常用的操作,因此ANSI C标准中;
把printf和scanf用于从标准输入获取信息和向标准输出显示信息的函数;
于是根据标准,输入输出可以简化为:
#include <stdio.h> int main(void) { char sbuf[100]; printf("Please input a string: "); scanf("%s",sbuf); printf("The input string is : \"%s\".\n",sbuf); return 0; }
int sprintf( char *buffer, const char *format, … );
把格式化的数据写入某个字符串中
int vsprintf(char *string, char *format, va_list param);
将param 按格式format写入字符串string中
注: 该函数会出现内存溢出情况,建议使用vsnprintf
scanf/fscanf/sscanf 函数基于基本同上;
格式化常用为printf/scanf ;
没必要例程测试;
- 文件操作open与fopen和read与fread的区别
- 文件操作open与fopen和read与fread的区别
- fread与read的区别---open和fopen的区别--fread函数和fwrite函数
- open,write,read与fopen,fwrite,fread的区别
- open/read/write和fopen/fread/fwrite的区别
- fopen/fread/fwrite和open/read/write函数的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite函数的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- open/read/write和fopen/fread/fwrite的区别
- fopen /open,read/write和fread/fwrite区别
- jQuery查看dom元素上绑定的事件列表
- java设计模式示例
- POJ-3041 Asteroids,二分匹配解决棋盘问题。
- HashMap和Hashtable的区别
- [完]Linux下安装Java环境
- 文件操作open与fopen和read与fread的区别
- Unity4.6 UI按钮绑定事件(一)
- MySQL知识点-总结
- BSOJ4835刷漆(Codechef October Challenge 2014:Remy paints the fence)
- C++要点
- R ggplot2画线形图
- Qt安装及交叉编译环境设置
- 单例模式
- 字符串全排列