Linux 文件IO与标准IO
按字符输入输出
fgetc与fputc实现文件复制(出现段错误 (核心已转储))(拷贝的文件 \ 文件尾没有换行符)
#include <stdio.h>
int main(int argc, char *argv[])
{ // 参数个数,字符指针数组
FILE *fps, *fpd; // 两个流指针,打开源文件与目标文件
int ch;//保存读出的字符
if (argc < 3)//检查命令行参数个数
{
printf("Usage : %s < src_file > < dst_file >\n", argv[0]);//正确格式
return -1;
}
if ((fps = fopen(argv[1], "r")) == NULL)//打开源文件,以只读方式“r” //注意括号,关系运算符==比赋值=优先
{
perror("fopen src file");
return -1;
}
if ((fps = fopen(argv[2], "w")) == NULL)//打开目标文件
{
perror("fopen dst file");
return -1;
}
while ((ch = fgetc(fps)) != EOF)//fgetc函数 > 成功时返回读取字符,文件末尾或者出错返回EOF
{
fputc(ch, fpd);
}
fclose(fps);
fclose(fpd);
return 0;
}
按行输入输出
与fgetc区别,fgets不能读取二进制文件,只可以读文本(因为fgets把0理解为终止符)
fgets遇到换行符则不会继续读了,会直接在后面追加一个\0,表示字符串结束
没有换行符,最多读取size-1个(最后一个存放\0)
数组名=数组首地址
结束符不写入流中
成功时返回字符个数,出错时返回EOF
puts 会追加’\n’
如何统计一个文本文件包含多少行?
fgets不能保证每一次都读一行(可能读到的不是完整一行)在数组缓存小的情况下
判断结束符前一个位置是不是换行符
buf[ strlen(buf) -1 ]//strlen 求数组长度 = 结束符下标
按对象输入输出
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);//缓冲区首地址,每个对象占大小,读取多少对象,流指针
//返回值 成功:实际读写对象个数,出错:EOF(-1),读到末尾:0
//既可以读文本,也可以读数据
使用fread与fwrite实现文件复制
#include <stdio.h>
#define N 64 // 定义一个大的缓冲区,用来一次操作多个对象
int main(int argc, char *argv[])
{
FILE *fps, *fpd;
char buf[N]; // 存放读出来的对象
int n; // 记录每一次实际读取的对象个数
if (argc < 3)
{
printf("Usage: %s <src_file> <dst_file>\n", argv[0]);
return -1;
}
if ((fps = fopen(argv[1], "r")) == NULL)
{
perror("fopen src file");
return -1;
}
if ((fpd = fopen(argv[2], "w")) == NULL)
{
perror("fopen dst file");
return -1;
}
while ((n = fread(buf, 1, N, fps)) > 0) // N读取多少对象 n实际读取对象个数
{
fwrite(buf, 1, n, fpd);
}
fclose(fps);
fclose(fpd);
return 0;
}
备份文件
./fread_fwrite fread_fwrite.c fread_fwrite.c.bak//.bak为备份文件,直接重命名即可使用
比较文件
diff -ruN 第一个文件名 第二个文件名
向流中缓冲区中输出字符串
流fprintf 缓冲区 sprintf
以指定格式"年月日"写入文件和缓冲区
#include <stdio.h>
#include <unistd.h> //sleep
#include <time.h> //time localtime
#include <string.h>
int main()
{
FILE *fp; // 打开文件,定义一个流指针
int line = 0; // 统计原先多少行
char buf[64];
time_t t;
struct tm *tp;//结构体指针,接收返回值
if ((fp = fopen("test.txt", "a+")) == NULL)
{
perror("fopen");
return -1;
}
while (fgets(buf, 64, fp) != NULL)
{
if (buf[strlen(buf) - 1] == '\n')
line++; // 判断是否读到完整的一行,如果有换行符(在结束符前),表明读到完整一行
}
while(1){
time(&t);
tp = localtime(&t);
fprintf(fp,"%02d,%d-%02d-%02d %02d:%02d:%02d\n", ++line,
tp ->tm_year+1900, tp ->tm_mon+1, tp ->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);//行号,年月日时分秒
fflush (fp);//强制刷新确保字符串从缓冲区写入文件里(默认普通文件打开是全缓冲,流关闭或缓冲区满了或出现换行 或fflush才会刷新)
sleep(1);//1秒睡眠
}
return 0;
}
刷新流(将流缓冲区的数据写入实际文件)
int fflush(FILE *stream);
定位流
int fseek(FILE *stream, long offset, int whence);//offset 基准点 //参数whence
//SEEK_SET/SEEK_CUR当前/SEEK_END
long ftell(FILE *stream);//当前读写位置
void rewind(FILE *stream);//起始位置
判断流出错
ferror ()//判断是否出错,返回1表示出错,否则返回0
feof()//返回1表示文件已到末尾,否则返回0
文件描述符
open
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//int open ( const char *pathname, int flags );
//参数1: 文件名,可包含路径
//参数2: 打开方式
// O_RDONLY只读
// O_WRONLY只写
// O_RDWR可读可写
// O_CREAT文件不存在,则创建( 需要第三个参数 )
// O_EXCL,文件存在则出错
// O_APPEND可追加
//返回值: 打开成功返回文件描述符,( 非负整数 )
//int open ( const char *pathname, int flags, mode_t mode );
//参数3 创建文件时指定新的文件的权限
int main(int argc, const char *argv[])
//argc (argument count) 参数个数 value 值
{
int fr = 0;
fr = open("1.txt", O_RDONLY);
if (fr < 0)
{
perror("open error");
return -1;
}
printf("open sucess\n");//标准输出流是行缓冲的,必须加\n
return 0;
}
动态库的制作
创建静态库(lib开始, .a结束,表示静态库)
库文件名: libhello.a
库名:hello
ar crs libhello.a hello.o
编译(-L指定路径 . 当前目录 -l 加库名,而不是库文件名)
gcc -o hello hello.c -L. -lhello
库中代码必须与位置无关
(1)
gcc -c -Wall -Werror -fPIC hello.c
(2)
gcc -c -fPIC hello hello.c
创建共享库(共享库不能以main为入口)
共享库命名规则(lib+库名.so(表示是一个共享库).1版本)
gcc -shared -o libcommon.so.1 hello.o
为共享库文件创建链接文件(链接文件必须以so结尾)
为了让编译器能找到共享库
ln -s libcommon.so.1 libcommon.so
编译test.c并链接共享库libcommon.so
先链接共享库,再链接静态库,没有–>报错
(若要指定静态库 加上 -static)
gcc -o test test.c -L. -lcommon
修改系统配置文件,添加库路径,再运行工具,把路径加到系统默认路径里
sudo vi /etc/ld.so.conf.d/my.conf
加入当前库所在路径
读取这个目录下所有配置文件,把所有路径中的库信息提取出来
sudo ldconfig
静态创建与动态创建
ar crs libhello.a hello.o
gcc -shared -o libcommon.so.1 hello.o
进程创建
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
pid_t pid = fork();//创建一个进程
if (pid < 0){
perror("fork err\n");
return -1;
}
if (pid > 0){
printf ("parent process,pid = %d\n", pid);
}
else if (pid == 0){
printf ("chlid process,pid = %d\n", pid);
}
return 0;
}
线程
安装pthread_create手册
sudo apt-get install glibc-doc
sudo apt-get install manpages-posix manpages-posix-dev
2个线程,同时操作全局变量
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int g_count = 0;
// 线程1---------g_count ++
void *thread1(void *arg)
{
while (1)
{
g_count++;
sleep(1);
printf("g_count = %d\n", g_count);
}
}
// 线程1---------g_count --
void *thread2(void *arg)
{
while (1)
{
g_count--;
sleep(1);
printf("g_count = %d\n", g_count);
}
}
int main(int argc, char const *argv[])
{
char str1[20] = "0123456789";
char str2[20] = "ABCDEFGHIJ";
// 创建线程
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, str1);
pthread_create(&t2, NULL, thread2, str2);
// 线程资源回收(等待线程退出,回收资源 阻塞)--(线程退出,自动回收(非阻塞)-> pthread_detach())
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}