Linux系統編程:文件的讀取寫入

一、read系統調用

一旦有了與一個打開文件描述相關連的文件描述符,只要該文件是用O_RDONLY或O_RDWR標誌打開的,就可以用read()系統調用從該文件中讀取字節 


函數原型:
ssize_t read(int fd, void *buf, size_t count);
參數:
fd :想要讀的文件的文件描述符
buf : 指向內存塊的指針,從文件中讀取來的字節放到這個內存塊中
count : 從該文件複製到buf中的字節個數
返回值:
如果出現錯誤,返回-1;讀文件結束,返回0;否則返回從該文件複製到規定的緩衝區中的字節數


二、write系統調用

用write()系統調用將數據寫到一個文件中 

函數原型:
ssize_t write(int fd, const void *buf, size_t count);
函數參數:
fd:要寫入的文件的文件描述符
buf: 指向內存塊的指針,從這個內存塊中讀取數據寫入 到文件中
count: 要寫入文件的字節個數
返回值:如果出現錯誤,返回-1;如果寫入成功,則返回寫入到文件中的字節個數


三、ioctl 函數

ioctl用於向設備發控制和配置命令,有些命令也需要讀寫一些數據,但這些數據是不能用read/write讀寫的,稱爲Out-of-band數據。也就是說,read/write讀寫的數據是in-band數據,是I/O操作的主體,而ioctl命令傳送的是控制信息,其中的數據是輔助的數據。例如,在串口線上收發數據通過read/write操作,而串口的波特率、校驗位、停止位通過ioctl設置,A/D轉換的結果通過read讀取,而A/D轉換的精度和工作頻率通過ioctl設置。

#include <sys/ioctl.h>

int ioctl(int d, int request, ...);
d是某個設備的文件描述符。request是ioctl的命令,可變參數取決於request,通常是一個指向變量或結構體的指針。若出錯則返回-1,若成功則返回其他值,返回值也是取決於request。
以下程序使用TIOCGWINSZ命令獲得終端設備的窗口大小。

#include <stdio.h>
#include <stdlib.h
#include <unistd.h>
#include <sys/ioctl.h
int main(void)
{
    struct winsize size;
    if (isatty(STDOUT_FILENO) == 0)
        exit(1);
    if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0)
    {
        perror("ioctl TIOCGWINSZ error");
        exit(1);
    }
    printf("%d rows, %d columns\n", size.ws_row, size.ws_col);
    return 0;
}

四、文件的隨機讀寫

到目前爲止的所有文件訪問都是順序訪問。這是因爲所有的讀和寫都從當前文件的偏移位置開始,然後文件偏移值自動地增加到剛好超出讀或寫結束時的位置,使它爲下一次訪問作好準備。
有個文件偏移這樣的機制,在Linux系統中,隨機訪問就變得很簡單,你所需做的只是將當前文件偏移值改變到有關的位置,它將迫使下一次read()或write()發生在這一位置。(除非文件打開時標誌有 O_APPEND,在這種情況下,任何write調用仍將發生在文件結束處)


lseek系統調用:

功能說明:通過指定相對於開始位置、當前位置或末尾位置的字節數來重定位,這取決於 lseek() 函數中指定的位置
函數原型:off_t lseek (int  fd,    off_t offset,   int base);

函數參數:

fd:需要設置的文件描述符

offset:偏移量

base:偏移基位置

返回值:返回新的文件偏移值

base 表示搜索的起始位置,有以下幾個值:(這些值定義在<unistd.h>)

base 文件位置

SEEK_SET 從文件開始處計算偏移
SEEK_CUR 從當前文件的偏移值計算偏移
SEEK_END 從文件的結束處計算偏移


注意:管道和socket是不能lseek的,否則返回ESPIPE錯誤(Invalid seek)。

示例程序如下:
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(int argc, char *argv[])
{
    int infd;
    int outfd;
    if (argc != 3)
    {
        fprintf(stderr, "Usage %s src dest\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    infd = open(argv[1], O_RDONLY);
    if (infd == -1)
        ERR_EXIT("open src error");
    if ((outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0664)) == -1)
        ERR_EXIT("open dest error");

    char buf[1024];
    ssize_t nread;
    while ((nread = read(infd, buf, 1024)) > 0)
        write(outfd, buf, nread); // 可以調用fsync同步內核緩衝區的數據到磁盤文件
    // 或者打開文件時標誌爲O_SYNC
    close(infd);
    close(outfd);
    /********************************************************************************************/

    infd = open("test.txt", O_RDONLY);
    if (infd == -1)
        ERR_EXIT("open error");
    char buf2[1024] = {0};
    int num = read(infd, buf2, 5);
    if (num == -1)
        ERR_EXIT("read error");
    num = lseek(infd, 0, SEEK_CUR); // 從當前位置偏移0個字節
    if (num == -1)
        ERR_EXIT("lseek");
    printf("current offset=%d\n", num);

    outfd = open("dest.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (outfd == -1)
        ERR_EXIT("open error");
    write(outfd,buf2, 5);
    close(infd);
    close(outfd);
    return 0;
}
struct stat結構體中的文件長度對應st_size字段,而文件使用的塊大小對應st_blksize字段,佔用塊數對應st_blocks字段。 大部分情況下面,st_size和st_blksize*st_blocks應該是很接近的,除非一種情況就是文件空洞。 一般對應於空洞文件來說,st_size可能很大,而實際佔用磁盤空間卻很少。



發佈了51 篇原創文章 · 獲贊 9 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章