2021年4月5日 星期一

C++ 讀取檔案 範例代碼 (行讀取 空格讀取 一次讀取整個文件)

C++ 讀取檔案 範例代碼 (行讀取 或 空格讀取)

純C的讀取可以看這篇站內文
https://charlottehong.blogspot.com/2021/04/c_7.html


大概是新手時常會遇到的問題,撇除大部分的教學都是C的方式讀取,更推薦用C++的方案讀取坑真的少很多,雖然現在主流教學還是用C讀取覺得很奇怪就是了,整理一篇給大家參考。

先簡單說一下會用到的物件是 fstream 基本已經封裝的超級容易使用了,不需要管指標什麼的直接上手就用就是了。

此文範例包含

  • 逐行讀取
  • 按照空格或跳行讀取
  • 一次性讀取整個文件
  • 按照所需長度讀取到C字串char*
  • 獲取檔案長度

開檔

就很簡單,直接宣告一個物件把檔名打進去就好

string buffer;
fstream fs("a.txt");
fs  >> buffer;

就這樣搞定。容易吧,直接一個箭頭就可以把檔案內容推到 string 裡面去了,只是基 stream 的關係遇到”空格”或是”跳行”就會停下來,所以 buffer 內容只會讀取到該處就停下來了,要繼續往下推才可以。

檢查是不是真的開成功了

這個程序沒讀到檔案也不會報錯,要檢查檔案是不是真的讀到了用 is_open() 檢查,有錯誤就自己噴一個例外標記一下哪行炸了吧。

if (!fs.is_open())
    throw runtime_error("Reading error.");

什麼時候讀完

是否推到檔案結束點,可以用 eof() 判定讀取指標是否到檔案結束標記了,當他回傳 1 的時候就是結束了。

cout << fs.eof() << endl;

所以直接把他放進for迴圈判斷中,讓他自己跑到結尾就可以了

fstream fs(file_name);
for(string str; fs >> str;) {
    cout << str << endl;
}

調整游標位置

檔案讀取是有一個類似游標的東西存在的,比如說你打開一個記事本游標一般就停在0的位置,讀取就是按方向鍵,一直往右邊刷這樣。

開檔的時候可以控制的屬性包含游標位置和權限、游標位置可以選擇起始位置在開頭或是結束處,這取決於你的行為如何,如果你要從檔案結尾處新增文字那當然一開始就設置在結尾處比較合適了。

檔案開啟後還可以調整游標位置,比如說

// 調整游標至,開始位置(beg)開始計算第0個。
fs.seekg(0, ios::beg);
// 調整游標至,當前位置(cur)開始計算第-1個。
fs.seekg(-1, ios::cur);
// 調整游標至,結束位置(end)開始計算第-2個。
fs.seekg(-2, ios::end);

順帶一提一個中文占2個位元,想跳過一個中文字要+2。

權限

就是對檔案是要讀檔還是寫入,參數在檔名之後,什麼都不打預設是可讀可寫。

// 只讀檔
fstream fs(file_name, ios::in);

// 只寫檔
fstream fs(file_name, ios::out);

// 可讀可寫(預設)
fstream fs(file_name, ios::out | ios::out);

還有兩個比較特別的參數 ate 和 app 詳情可以參考這裡。
https://charlottehong.blogspot.com/2017/05/c-iosapp-iosate.html

獲取檔案大小或長度

檔案大小指的其實就是游標最尾端的位置在哪裡,利用剛剛那個移動到最尾端之後回報他的所在位置就可以得到檔案大小了

size_t FileSize(fstream& fs) {
    size_t curr = fs.tellg();
    fs.seekg(0, ios::end);
    size_t len = fs.tellg();
    fs.seekg(curr);
    return len;
};

這是一個封裝好的函式,多寫一個功能是把游標恢復到原本的位置,執行的話像這樣。

fstream fs(file_name, ios::in);
if (!fs.is_open())
    throw runtime_error("Reading error.");

size_t fileSize = FileSize(fs);

size_t 是 unsigned long long 無負號的長長整數。

關閉檔案

結束對檔案的讀取,通常沒用到建議就馬上關了,會出問題的當你的程序不只一個地方讀取檔案的時候,可能會出現同時兩個物件讀同一個檔案,這就不行了。讀取的時候檔案會被占用,不能再有第二個物件來讀取。

fs.close();

順帶一提當物件生命周期結束時會自動關閉檔案的,底下的範例我把讀檔寫在函式內,關檔寫在最後一行其實是可以省略的,因為函式馬上就結束了意味著,物件的生命週期結束了,解構子會自動關閉檔案的,不寫也是合法不會出問題的。(但是我推薦養成習慣寫上,哪天花一個小時Debug最後才發現沒關檔真的會氣死)

最後是讀取到 C 字串

有些人可能一開始寫的代碼是用 char 完成的一時之間實在不轉過來,有兩個解法。一個是直接把 string 轉 char* 就好了,這很容易有內建函式。


string str="chg";
const char* c_str = str.c_str();

如果要直接轉進去 char* 就是不想用 string 那還是有函式可以處理

// 按照所需長度讀取到C字串char*
void ReadFile_buffer(const string file_name) {
    fstream fs(file_name, ios::in);
    if (!fs.is_open())
        throw runtime_error("Reading error.");
    char buffer[256]{};
    size_t readSize = sizeof(buffer);
    fs.read(buffer, readSize);
    cout << buffer << endl;
    fs.close();
}

順帶一提這裡的 read() 是可以換成 getline() 的

範例代碼

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

// 逐行讀取
void ReadFile_line(const string file_name) {
    fstream fs(file_name, ios::in);
    if (!fs.is_open())
        throw runtime_error("Reading error.");

    for (string str; getline(fs, str);){
        cout << str << endl;
    } fs.seekg(0, fs.beg);
    fs.close();
}

// 按照空格或跳行讀取
void ReadFile_space(const string file_name) {
    fstream fs(file_name, ios::in);
    if (!fs.is_open())
        throw runtime_error("Reading error.");
    for(string str; fs >> str;) {
        cout << str << endl;
    } fs.seekg(0, ios::beg);
    fs.close();
}

// 一次性讀取整個文件
void ReadFile_all(const string file_name){
    fstream fs(file_name, ios::in);
    if (!fs.is_open())
        throw runtime_error("Reading error.");
    string str(
        (istreambuf_iterator<char>(fs)),
        istreambuf_iterator<char>()
    );
    cout << str << endl;
    fs.close();
}

// 按照所需長度讀取到C字串char*
void ReadFile_buffer(const string file_name) {
    fstream fs(file_name, ios::in);
    if (!fs.is_open())
        throw runtime_error("Reading error.");
    char buffer[256]{};
    size_t readSize = sizeof(buffer);
    fs.getline(buffer, readSize);
    cout << buffer << endl;
    fs.close();
}

// 獲取檔案長度
size_t FileSize(fstream& fs) {
    size_t curr = fs.tellg();
    fs.seekg(0, ios::end);
    size_t len = fs.tellg();
    fs.seekg(curr);
    return len;
};

int main(int argc, char const* argv[]) {
    string filename = "a.txt";

    //ReadFile_line(filename);
    //ReadFile_space(filename);
    ReadFile_all(filename);
    //ReadFile_buffer(filename);

    return 0;
}

2021年3月22日 星期一

Eclipse 使用 junit5 測試單元函式

Eclipse 使用 junit5 測試單元函式

貌似跟以前的方式差異有點大,找了好幾篇文章都沒成功,最後在YT上看到影片才成功的,貼上來記錄一下。

直接在要測試的函式上面打 @Test 然滑鼠移動到錯誤停留1秒,跳出修正視窗,直接按修正。



修正之後,對要測試的函式按右鍵,測試


直接就有成果了


要移除unit5從你的專案按右鍵屬性,進去刪除。










2021年2月6日 星期六

Youtube 如何掛載 離線字幕檔

Youtube 如何掛載 離線字幕檔
兩個方法,但都有一點小麻煩就是了。

chrome插件實現

插件是這個:Dualsub

安裝完畢之後對瀏覽器右上角的Dualsub圖標,按右鍵管理擴充功能進入後台

進去之後先選到插件內容

1. 進來之後先打個名稱你自己可以辨別就好等一下會用到
2. 字幕類型按照字幕格式去選,選錯會沒辦法掛載
3. 最後代碼的字幕就直接把字幕內容全貼上去

然後回到插件狀態頁面把剛剛創建的字幕打勾

然後回到YT上的頁面,記得先按一下重新整理然後等個1秒左右再按右上角的圖示。

選擇剛剛創建的字幕。字幕就能正常播放了。(例中字幕跟影片是不搭的)


利用potplyer播放器掛載本機字幕

其實就是potplayer可以播線上的檔案,掛載當然就是直接拉進去而已。或是實現Youtube補禎之類的。

載點:PotPlayer_1.7.20977_setup_azo

版本我挑過了是2019.11月版本的,12月開始有強迫推廣告。20年開始內帶流氓軟體 Segurazo,建議不要更新也不要裝最新版的,沒人知道有沒有拿掉。

如何載入線上片源從這裡 新增連結。或直接按快捷 CTRL+U 比較快。


然後網址貼上就完事了

字幕檔跟看離線的一樣,直接拉進去就可以。

2021年2月2日 星期二

10句 能夠有兩種解釋的日文例句

10句 能夠有兩種解釋的日文例句

今天上課的內容,覺得還蠻有趣的把句子跟解釋記錄下來吧。

結婚.恋愛

ファーストキスの相手は独身だった

  • 我初吻的對象是單身(回憶過往那時候他單身)
  • 我初吻的對象是單身(聚會上見到曾經的對象向他詢問了近期如何,現在才知道他已經單身了)

近くにいられると恥ずかしいけど少しうれしい

  • 對方接近自己
  • 自己去接近對方

まるで僕の奥さんみたいだね

  • 就好像自己真實的妻子一樣
  • 動作親密彷彿自己的妻子一樣

田中さんが好きなのは私だ

  • が當主語。田中喜歡的人是我。
  • 喜歡田中的人是我。

学校.会社

先生に見えないとうにした

  • 把東西藏好不讓老師看到
  • 隱藏自己身為老師的職業

喧嘩をすほど仲が良くなった

  • 越吵感情越好
  • 要好的程度就好像能吵架的程度一樣

電車で読書しているサラリーマンに驚かされた

  • 看書的上班族做了什麼事情害我嚇到了
  • 居然有人在電車上看書,被這一情景嚇到了

社長に推薦されたんだよ

  • 被社長推薦了
  • 主語被推薦成為社長這個職務

家族

子供と一緒に猫をソファーに座らせた

  • 讓小孩和貓坐到沙發上
  • 和小孩一起讓小貓坐到沙發上

部屋が明るいといいね

  • 這房間真亮很好
  • 要是能夠在亮一點就好了

息子の家は質素でいい

  • 兒子的家簡單就好了不用搞太麻煩
  • 兒子的家簡簡單單的看上去真棒

困った

エレベーターで遊ばないでください

  • 不要在電梯玩
  • 因為電梯的關係請不要玩耍

トイレを探してください

  • 想去廁所,去找廁所
  • 東西不見了,去廁所找找

飲食

アルコール類は飲ません

  • 我不喝
  • 我不能喝

2021年1月28日 星期四

Aegisub 新增自訂快捷鍵 無效沒有作用

Aegisub 新增自訂快捷鍵 無效沒有作用

會發現這個問題是我想新增「播放當前行」,影像會跟著播放的不是空白建的單純播放聲音的快捷鍵。快捷鍵指令是 video/play/line

新增的快捷都沒有作用之外奇怪的是,新增的會跑到最下面又多出一個分類,比如說在視訊裡新增一個,底下會多出一個視訊的分類,然後剛剛新增的就在裡面。

原因

找了半天才找到原因是

改語言後不支持新增熱鍵

也就是說先改回去英文版就可以正常新增了

快捷鍵分類與指令

另外設定檔內的大分類,預設編碼、音效、總是、樣式助手等這些。
意思是這個快捷在哪些地方生效。

比如說

  • 字幕編輯方塊鍵只有當你在編輯字幕時才起作用
  • 視訊裡的快捷鍵只有當你點擊一下視訊時才起作用

除此之外快捷鍵不只原本選項內的,有些不一定有寫出來,程序裡面看的到的按鈕都可以設定成快捷鍵,詳細的指令可以參考官方的手冊

https://aegi.vmoe.info/docs/3.2/Commands/zh_TW/

設定檔位置

怎麼發現是我去把設定檔翻出來直接修改才發現的,設定檔位置在

%USERPROFILE%\AppData\Roaming\Aegisub\hotkey.json

裡面一看就發新用中文語言新增快捷鍵會額外創建一個新的分類,比如說 Always 就新創一個 總是。但是程序實際跑的時候只會偵測到 Always 而不會偵測到 總是 所以就沒用了。

不想改語言也可以直接修改設定檔,不過這樣你要重啟 Aegisub 才能生效。

2021年1月21日 星期四

新版 Win10 被停用的音效裝置 在哪裡

新版 Win10 被停用的音效裝置 在哪裡

今天在找停用裝置的時候找了一下,發現新版Win10(2004)的UI已經改版了,不在原本的聲音控制台裡面。

位置在[設定->系統->音效]然後下面的管理音效裝置。



點進去就可以找到被停用的裝置了。