UNIX/LINUX,Linux操作系統-標準IO庫(2)

 2023-12-09 阅读 39 评论 0

摘要:Linux操作系統—標準IO庫(2)(2015-8-4) 分類:Linux操作系統 ??打開一個流后,可采用三種不同類型的非格式化I/O對其進行讀,寫操作。 1. 每次讀取一個字符的I/O 2. 每次一行的I/O。以換行符標示一行的終止 3. 二進制I/O。每次I/O操作讀或寫一定數量的對象&

Linux操作系統—標準IO庫(2)(2015-8-4)

分類:Linux操作系統

??打開一個流后,可采用三種不同類型的非格式化I/O對其進行讀,寫操作。
1. 每次讀取一個字符的I/O
2. 每次一行的I/O。以換行符標示一行的終止
3. 二進制I/O。每次I/O操作讀或寫一定數量的對象,而每個對象具有指定的長度。

??前兩者可以說是基于字符和行的I/O。后者叫做二進制I/O。

基于字符和行的I/O

字符I/O

讀字符

??使用下面的三個函數可以一次讀取一個字符

#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);

UNIX/LINUX,??對于這些函數的區別,作為初學者,我不想太糾結,這不是重點。等以后使用熟練再深究也不遲。暫時先記著這個:函數getchar等同于getc(stdin)(這就意味著getchar是特定地從stdin中讀取數據)。
??參數stream表示已打開并準備從其中讀取數據的流。成功時,三個函數均返回所讀取的字符,出錯或已到達文件尾端時返回EOF。
&esmp;?下面來講一講非常有意思東西。大家可能發現了,這三個函數返回的是字符,然而它們的函數類型卻是int型的,這是怎么回事呢?
??這三個函數以unsigned char類型轉換為int的方式返回下一個字符。說明為不帶符號的理由是,即使所讀字節最高位為1也不會返回負數。要求整形返回值的理由是,這樣可以返回已發生錯誤或已達到文件尾端的指示值EOF(-1)。

小插曲:回送字符
??當讀一個輸入流時,經常會用到回送字符操作。回送字符操作通常用于需要根據下一個字符的值來決定如何處理當前字符的情況。處理這種情況時,需要在讀出下一個字符以后,能將其送回流緩沖區,以便下一次輸入時再返回該字符。
??標準I/O庫提供了ungetc函數以支持字符回送操作。該函數的原型如下。

#include <stdio.h>
int ungetc(int c, FILE *stream);

??說明:參數c是要送回流中的字符,stream是所操作的流。成功時返回c,失敗時返回EOF。送到流中的字符以后又可以從流中讀出,但讀出的順序與送回的順序相反。回送的字符,不一定必須是上一次讀到的字符,但是不能回送EOF。但已到達文件尾端時,扔可以回送一個字符。下次讀將返回該字符,再次讀時才返回EOF。之所以能這樣做的原因是一次成功的ungetc調用會清除該流的文件結束指示。

判斷流結束或出錯

??在大多數的FILE對象的實現中都為每個流保持了兩個標志:文件結束標志和文件出錯標志。feof函數和ferror函數分別根據這兩個標志來判斷流是否結束或著流是否出錯。因為到達文件尾端和出錯時,三個字符讀取函數的返回值都是EOF,所以應當通過調用feof和ferror函數區分這兩種情況。(看到這,終于明白了,這兩個函數的存在是為了分辨,當這三個函數返回的是EOF時,到底是因為流結束還是因為是出錯了)。這兩個函數的原型如下:

#include <stdio.h>
int feof(FILE *stream);
int ferror(FILE *stream);

docker底層原理???說明:參數stream為要判斷是否已到達文件尾或出錯的流。當流已到達文件尾時,feof返回非0值,否則返回0值。當流出錯時,ferror返回非0,否則返回0。
??那么,如何清除FILE對象中的文件結束標志和出錯標志呢?可以使用clearerr函數,該函數的原型如下:

#include <stdio.h>
void clearerr (FILE *stream);

寫字符

??使用下列字符可以一次寫入一個字符

#include <stdio.h>
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);

??與字符輸入函數一樣,putchar(c)與putc(c, stdout)等價。這些函數的每一次調用會使當前讀寫位置向文件尾部移動一個字符,即每次寫入的位置是上一次寫入位置之后的一個字節。
??成功時,三個函數均返回寫入的字符,出錯時返回EOF。

實踐篇

??初學者嘛,盡情地實踐,有了想法就把它實現出來,盡量把學到的東西都練習一遍。
目標一:從標準輸入中讀取字符并將其保存在名為data.txt的文件中
??這個并不難,可以很輕松地寫出來。注意在命令行中,按下Ctrl + D可以向輸入流中產生EOF值。

/** Name : IO001.c* Author : LazyBone1994* Date : 2015-8-4 18:00*
*/#include <stdio.h>
#include <stdlib.h>/* 從標準輸入中讀取字符并將其保存在名為data.txt的文件中 */
int main(int argc, char *argv[])
{FILE *fp;int c;if ((fp = fopen("data.txt", "w")) == NULL){         /* 無法創建文件 */printf("Cannot create data.txt file!\n");exit(-1);}while ((c = getchar()) != EOF)                      /* 從標準輸入讀取字符 */fputc(c, fp);fclose(fp);                                         /* 關閉流 */return 0;
}

docker jvm。??查看一下結果唄。實現了目標

biantiao@lazybone1994-ThinkPad-E430:~/桌面$ gcc -o IO001 IO001.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./IO001
Hello World !
This is a sample test.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ls
data.txt  IO001  IO001.c  IO001.c~  IO001.C~
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ cat data.txt
Hello World !
This is a sample test.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$

??初學者就要盡情地嘗試。改造一下,改哪里?將getchar語句改掉改成一個等效的語句。

/** Name : IO001.c* Author : LazyBone1994* Date : 2015-8-4 18:00*
*/#include <stdio.h>
#include <stdlib.h>/* 從標準輸入中讀取字符并將其保存在名為data.txt的文件中 */
int main(int argc, char *argv[])
{FILE *fp;int c;if ((fp = fopen("data.txt", "w")) == NULL){         /* 無法創建文件 */printf("Cannot create data.txt file!\n");exit(-1);}while ((c = getc(stdin)) != EOF)                    /* 從標準輸入讀取字符 */fputc(c, fp);fclose(fp);                                         /* 關閉流 */return 0;
}

??看看結果如何。實現了目標。

biantiao@lazybone1994-ThinkPad-E430:~/桌面$ gedit IO001.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ gcc -o IO001 IO001.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ls
IO001  IO001.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./IO001
Hello, My CSDN ID is LazyBone1994.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ls
data.txt  IO001  IO001.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ cat data.txt
Hello, My CSDN ID is LazyBone1994.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$

目標二:從標準輸入中構造文本data.txt,并實現copyFile函數復制data.txt文件
??按照順序來寫吧,如下:

/** Name : IO002.c* Author : LazyBone1994* Date : 2015-8-5 11:23
*/#include <stdio.h>
#include <stdlib.h>
#define     ERROR       -2
#define     OK          1/* source為要被復制的文件的指針,filename為復件的文件名 */
int copyFile(FILE *source, char *filename)
{char c;FILE *newFile = NULL;if (source == NULL){printf("Source file error!\n");return ERROR;}if (filename == NULL){printf("Warning:The new file will use the default name.\n");filename = "a.txt";}newFile = fopen(filename, "w");                 /* 打開文件的另外兩個是fdopen和freopen,它們在這里并不適用 */if (newFile == NULL){printf("Cannot create new file.\n");return ERROR;}while ((c = getc(source)) != EOF){              /* 可用fgetc替換,另一個函數getchar在這并不適用 */putc(c, newFile);                           /* 可用fputc替換,另一個函數putchar在這并不適用 */}fclose(newFile);return OK;
}/* 從標準輸入中構造文本data.txt,并實現copyFile函數復制data.txt文件 */
int main(int argc, char *argv[])
{int flag;char c;char filename[33];FILE *fp;printf("Creating data.txt begins...\n");if ((fp = fopen("data.txt", "w")) == NULL){printf("Cannot create file data.txt.\n");exit(-1);}printf("Please input the content of data.txt(end with Ctrl + D):\n");while ((c = getchar()) != EOF){fputc(c, fp);}fclose(fp);fp = fopen("data.txt","r");printf("Create file data.txt is done.\n");printf("Copy new file is begining...\n");printf("Please input new file's name(end with Ctrl + D):");fgets(filename, 33, stdin);putchar('\n');flag = copyFile(fp, filename);if (flag == OK)printf("Copy new file is done.\n");elseprintf("Copy new file failed.\n");return 0;
}

docker.io是什么。??修改了好久(沒辦法比較菜),終于能行了,還算比較友好的界面提示。查看結果了。

biantiao@lazybone1994-ThinkPad-E430:~/桌面$ gcc -o IO002 IO002.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./IO002
Creating data.txt begins...
Please input the content of data.txt(end with Ctrl + D):
Hello everybody!
This is all the words that will be copied later.
Create file data.txt is done.
Copy new file is begining...
Please input new file's name(end with Ctrl + D):newFile.txt
Copy new file is done.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ls
data.txt  IO002  IO002.c  IO002.c~  newFile.txt
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ cat newFile.txt
Hello everybody!
This is all the words that will be copied later.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$

??怎么說呢?當所有的輸入都不為空的時候,確實能夠復制成功。但是但你輸入的新文件的名稱為空時,復制的新文件的名字將會出現亂碼。為什么?因為filename這個指針從來不為空(即使你不輸入它)所以函數中的if (filename == NULL)就成了無用的了,實際的文件名在你不輸入的情況下取的是垃圾值。怎么修改呢?暫時先不想,往下繼續。想好的朋友可以告訴我。
??發現自己的C語言功底實在是菜。特別是在字符串,數組,指針,傳指針調用結合在一起的情況下,就懵了。得好好惡補。

行I/O

讀行

??使用以下兩個函數可以從流中一次讀取一行文本。

#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);

??各參數和返回值含義如下:
1. s:輸入緩存
2. size:輸入緩存大小
3. stream:流文件指針
4. 返回值

  • 成功時返回指向緩存的指針
  • 失敗時或處于文件尾端時返回NULL,同時設置errno

??fgets從指定的流讀,而gets從標準輸入讀。每調用一次fgets會使當前讀寫位置向文件尾部移動所讀取到的字符數,以保證每次讀取的是上一次讀取位置之后的位置。
??對于fgets,必須指定緩存的長度size。次函數一直讀取到下一個換行符為止,但是不超過size - 1個字符,讀入的字符被送入緩存。該緩存總是以null字符結尾。如果該行(包括最后一個換行符)的字符數超過size - 1,則只返回一個不完整的行,而且緩存仍以null字符結尾。對fgets的下一次調用會繼續讀取該行剩余的字符。
??gets并不招人待見,因為使用它非常不安全,而且在新的C語言標準中它已經被踢出去了,只是為了向后兼容,使用它仍可以通過編譯。記住一點:fgets會將讀取到的換行符送入緩存,而gets并不保存換行符。

寫行

??使用下面兩個函數可向流中一次寫入一行文本。

#include <stdio.h>
int fputs(const char *s, FILE *stream);
int puts(const char *s);

??這兩個函數的各參數和返回值的含義如下:
1. s:待輸出的字符串,應以null終止
2. stream:流文件指針
3. 返回值

  • 成功時返回非負數
  • 失敗時返回EOF(-1)

??函數fputs將一個以null符終止的字符寫到指定的流,終止符null本身并不寫出。但是,puts在輸出指定的字符串后又附加地將一個換行符寫到標準輸出。

實踐篇

目標一:反復從標準輸入中讀取行并將其保存在一個文本中
??代碼如下嘍

/** Name : IO003.c* Author : LazyBone1994* Date : 2015-8-6 15:35
*/#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define     BUFFSIZE        81void DeleteCharEnter(char *s)
{if (s == NULL)return ;for (; (*s) != '\0'; s++){if (*s == '\n')*s = '\0';}
}/* 反復從標準輸入中讀取行并將其保存在一個文本中 */
int main(int argc, char *argv[])
{FILE *fp = NULL;char filename[33], str[BUFFSIZE];printf("Please input the filename(end with Enter):");fgets(filename, 33, stdin);DeleteCharEnter(filename);if ((fp = fopen(filename, "w")) == NULL){puts("Error : Cannot open file for writing.");exit(-1);}printf("Please input the file content:\n");             /* 輸入quit結束 */while (strcmp(fgets(str, BUFFSIZE, stdin), "quit\n") != 0){fputs(str, fp);}fclose(fp);return 0;
}

??編譯并運行

biantiao@lazybone1994-ThinkPad-E430:~/桌面$ gcc -o IO003 IO003.c
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./IO003
Please input the filename(end with Enter):NewFIle
Please input the file content:
Hello World!
I am LazyBone1994.
quit
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ls
IO003  IO003.c  NewFIle
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ cat NewFIle
Hello World!
I am LazyBone1994.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$

目標二:從文件中讀取字符,并將其顯示在標準輸出中
??就利用剛才生成的NewFile文件吧,代碼如下嘍

/** Name : IO004.c* Author : LazyBone1994* Date : 2015-8-6 16:23
*/#include <stdio.h>
#include <stdlib.h>
#define     BUFFSIZE    80/* 從文件中讀取字符,并將其顯示在標準輸出中 */
int main(int argc, char *argv[])
{char buf[BUFFSIZE];FILE *fp;fp = fopen("NewFIle", "r");if (fp == NULL){puts("Error : Cannot open file for reading.");exit(-1);}while((fgets(buf, BUFFSIZE, fp)) != NULL){fputs(buf, stdout);}fclose(fp);return 0;
}

??編譯并運行:

biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ls
IO004  IO004.c  NewFIle
biantiao@lazybone1994-ThinkPad-E430:~/桌面$ ./IO004
Hello World!
I am LazyBone1994.
biantiao@lazybone1994-ThinkPad-E430:~/桌面$

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/195877.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息