前言
上一篇文章,主講了 Open/Close 的 API ,以及簡(jiǎn)單的用法.
代碼 Git 地址 SuzhenProjects/ApueProject
常用函數(shù)復(fù)習(xí)
-
open
打開(kāi)或者創(chuàng)建一個(gè)用來(lái)讀/寫(xiě)的文件 -
read
讀取用戶指定的 Input -
write
寫(xiě)入到指定的 Output -
lseek
重新定位讀寫(xiě)游標(biāo)的位置 -
close
刪除(關(guān)閉)一個(gè)文件描述符
Tips: 通過(guò) man 2 <Command> 可以查詢你系統(tǒng)的這些 API 檔案
Read 函數(shù) ssize_t read(int fildes, void *buf, size_t nbyte);
-
fildes
文件描述符,可以是一個(gè)簡(jiǎn)單的文件,也可以是一個(gè)網(wǎng)絡(luò)套接字 -
buf
讀取數(shù)據(jù)的data, 會(huì)被存儲(chǔ)到buf
中 -
nbyte
期望一次性讀取的數(shù)據(jù)大小,注意這是一個(gè)無(wú)符號(hào)數(shù) -
返回值
- 返回值是一個(gè)有符號(hào)數(shù),
0
成功,-1
失敗. - 如果失敗,需要檢查
errno
- 返回值是一個(gè)有符號(hào)數(shù),
Write 函數(shù) ssize_t write(int fildes, const void *buf, size_t nbyte);
-
fildes
文件描述符,可以是一個(gè)簡(jiǎn)單的文件,也可以是一個(gè)網(wǎng)絡(luò)套接字 -
buf
數(shù)據(jù)區(qū),nbyte
長(zhǎng)度的數(shù)據(jù)傳送到文件描述符中 -
nbyte
期望寫(xiě)入的數(shù)據(jù)長(zhǎng)度,注意這是一個(gè)無(wú)符號(hào)數(shù) -
返回值
- 返回值是一個(gè)有符號(hào)數(shù),
0
成功,-1
失敗. - 如果失敗,需要檢查
errno
- 返回值是一個(gè)有符號(hào)數(shù),
Tips:
read
和write
函數(shù),兩者形式上,基本類(lèi)似,利用這點(diǎn),可以很方便的進(jìn)行記憶
Lseek 函數(shù) off_t lseek(int fildes, off_t offset, int whence);
offset
參數(shù)具體意義,是根據(jù) whence
來(lái)確定的.
lseek
如果作用在管道, FIFO,或者網(wǎng)絡(luò)套接字上,會(huì)返回錯(cuò)誤ESPIPE
fildes
文件描述符,一般我們用在一個(gè)本地文件上-
offset
和whence
作用whence offset意義 SEEK_SET 偏移到指定的 offset
上SEEK_CUR 在當(dāng)前的讀寫(xiě)偏移量的基礎(chǔ)上,繼續(xù)偏移 offset
個(gè)位置,offset
可正可負(fù)SEEK_END 在當(dāng)前文件長(zhǎng)度的基礎(chǔ)上,為文件長(zhǎng)度增加 offset
,offset
可正可負(fù) -
返回值
- 如果執(zhí)行成功,返回當(dāng)前最新的偏移量
實(shí)戰(zhàn) C++
我們?cè)O(shè)計(jì)的這段程序,需要先在程序運(yùn)行目錄創(chuàng)建一個(gè)
test.txt
文件.隨機(jī)寫(xiě)入一些數(shù)據(jù),然后保存并關(guān)閉該文件.
//
// Created by suzhen on 05/01/2018.
//
#include <unistd.h>
#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <cerrno>
int main(int argc, char **argv) {
static constexpr char TEST_FILE[]{"test.txt"};
int test_file_fd = ::open(TEST_FILE, O_RDWR, 0644);
if (test_file_fd < 0) {
printf("%s 文件打開(kāi)失敗, %s\n", TEST_FILE, strerror(errno));
return 1;
}
//注意,這段程序其實(shí)我們只能讀取 0xFF-1 個(gè)c har
constexpr size_t read_buf_size = 0xFF;
char read_buf[read_buf_size]{'\0'};
ssize_t read_sz = ::read(test_file_fd, (void *) read_buf, read_buf_size - 1);
if (read_sz < 0) {
printf("文件讀取失敗, %s\n", strerror(errno));
::close(test_file_fd);
return 2;
}
printf("文件內(nèi)容是 \n%s\n", read_buf);
//追加一段內(nèi)容,由于 read 的作用,當(dāng)前讀寫(xiě)游標(biāo)已經(jīng)移動(dòng)到了末尾
constexpr char append_string[]{"\n我直接追加到末尾!"};
ssize_t write_sz = ::write(test_file_fd, append_string, strlen(append_string));
if (write_sz < 0) {
printf("文件寫(xiě)入失敗, %s\n", strerror(errno));
::close(test_file_fd);
return 3;
}
//seek到指定位置寫(xiě),這里為了簡(jiǎn)單,直接 seek 到文件的開(kāi)頭的位置
off_t seek_offset = lseek(test_file_fd, 0, SEEK_SET);
if (seek_offset != 0) {
printf("偏移到文件開(kāi)始的位置,操作失敗\n");
::close(test_file_fd);
return 4;
}
printf("成功偏移到文件開(kāi)始的位置\n");
constexpr char insert_string[]{"我直接插入到頭部!這會(huì)覆蓋之前的內(nèi)容"};
ssize_t insert_sz = ::write(test_file_fd, insert_string, strlen(insert_string));
if (insert_sz < 0 || insert_sz != strlen(insert_string)) {
printf("在文件頭部寫(xiě)入數(shù)據(jù),操作失敗\n");
::close(test_file_fd);
return 5;
}
return 0;
}
重點(diǎn)
使用 read
,write
,close
這三個(gè)函數(shù),仿佛就在操作數(shù)組一樣,我們沒(méi)法很輕松的在文件頭插入一行數(shù)據(jù),只能在末尾寫(xiě)入一段字符.
一旦在文件的頭部進(jìn)行 write
文件頭部的數(shù)據(jù),直接會(huì)覆蓋之前的內(nèi)容,這也許不是我們想要的操作,如果你想要更加直觀的操作一個(gè)文件,我們可以使用 fopen
,fput
... 等等專(zhuān)業(yè)面向文件的 API.