linux系統編程之檔案與I/O(二):檔案的讀取寫入

來源:互聯網
上載者:User

一、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命令獲得終端裝置的視窗大小。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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 從檔案的結束處計算位移


樣本程式如下:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/*************************************************************************
    > File Name: file_cp.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#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);
    /********************************************************************************************/

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

    fd = open("hole.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (fd == -1)
        ERR_EXIT("open error");
    write(fd, "ABCDE", 5);
    ret = lseek(fd, 1012 * 1024 * 1024, SEEK_CUR);
    if (ret == -1)
        ERR_EXIT("lseek error");
    write(fd, "hello", 5);
    /* 中間的Null 字元不佔用磁碟空間,如ls -lh hole.txt 與 du -h hole.txt
     * 看到的檔案大小不一樣*/
    close(fd);

    return 0;
}


程式的前部分實現了拷貝檔案的準系統,後部分樣本了lseek的用法,因為有些程式需要輸入參數,且討論程式輸出結果也比較繁瑣,比如上述關於hole.txt檔案的實際大小問題,大家可以自己拷貝程式進行測試,印象也更加深刻。


參考:《APUE》

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.