主頁 > 移動端開發 > 在C 中讀取檔案并在行之間進行比較

在C 中讀取檔案并在行之間進行比較

2021-11-06 23:04:34 移動端開發

假設 file.txt 包含如下隨機檔案名:

a.cpp
b.txt
c.java
d.cpp
...

這個想法是我想從檔案名中將檔案擴展名作為子字串,然后在擴展名之間進行比較以查找重復項。
這是我的代碼:

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

    int main()
    {

    ifstream infile;   
    infile.open("file.txt"); 

    string str,sub;
    int count,pos=0;

    while(infile>>str)  
    {
    pos=str.find(".");
    sub=str.substr(pos 1);
    
    
    if(sub==?)
        // I stopped here
        count  ;  
    
    }
    cout<<count;    
    return 0;
    }

我是 C 的新手,所以我不知道使用哪個函式跳轉到下一行,我搜索了很多來弄清楚,但沒有。

uj5u.com熱心網友回復:

您可以使用以下程式列印輸入檔案中每個擴展名對應的計數。該程式用于std::map跟蹤計數。


#include <iostream>
#include <map>
#include <fstream>

int main()
{
   
    std::ifstream inputFile("input.txt");
    
    std::map<std::string, int> countExtOccurence; //this will count how many time each extension occurred
    
    std::string name, extension;
    if(inputFile)
    {
        while(std::getline(inputFile, name, '.')) //this will read upto a . occurrs 
        {
            std::getline(inputFile, extension, '\n');
            {
                countExtOccurence[extension]  ; //increase the count corresponding to a given extension
            }
        }
    }
    else 
    {
        std::cout<<"input file cannot be opened"<<std::endl;
    }
    inputFile.close();
    
    //lets print out how many times each extensino occurred in the file 
    for(const std::pair<std::string, int> &pairElem: countExtOccurence)
    {
        std::cout<<pairElem.first<<" occurred: "<<pairElem.second<<" time"<<std::endl;
    }
    return 0;
}

上面程式的輸出可以在這里看到

uj5u.com熱心網友回復:

好的,您想讀取存盤在檔案中的檔案名,然后獲取擴展名的計數。

這看起來很簡單,但事實并非如此。原因是,現在的檔案名可以包含所有型別的特殊字符。其中可能有空格,也可能有多個點 ('.') 。根據檔案系統的不同,可能會有斜線“/”(如在 Unix/Linux 中)或反斜線“\”(如在 Windows 系統中)作為分隔符。還有沒有擴展名的檔案名和以句點開頭的特殊檔案。(如“.profile”)。所以基本上沒那么容易。

即使只有檔案名,您應該做的最少操作是從字串的右端搜索點“.”,(可能)表示檔案擴展名。永遠不要從左側。因此,在您的情況下,您應該使用rfind而不是find.

現在,對于您的問題,如何閱讀下一行。您使用格式化輸入函式的方法適用于示例源檔案中顯示的檔案名,但如果檔案名中有空格,則不起作用。例如,您的陳述句infile>>str將在第一個空格字符后停止轉換。

示例:檔案名是“Hello World.txt”,那么“str”將只包含“Hello”,下一次讀取將包含“World.txt”。因此,您應該閱讀帶有專用函式的完整行std::getline在此處閱讀說明

有了它,您可以逐行閱讀:while(std::getline(inputFile,str)

然后,稍后您可以拆分擴展并對其進行計數。

對于擴展的拆分,我已經給了你一個提示和一些警告。但是,非常好,C 為您提供了一個隨時可用的解決方案。此處filesystem描述-library 這擁有您需要的一切,隨時可用。

特別有用的是路徑型別,它有一個功能擴展這將為您完成所有細節。

因為它這樣做,我強烈建議使用它。

現在,生活變得簡單。請參閱以下示例:

#include <iostream>
#include <string>
#include <filesystem>

// Namespace alias to save a lot of typing work . . .
namespace fs = std::filesystem;

int main() {
    // Read any kind of filename from the user
    std::string line{};   std:getline(std::cin, line);

    // Print the extension
    std::cout << fs::path{ line }.extension().string();
}

因此,無需擔心作業系統和任何型別的檔案名。它只會為您完成所有基礎作業。


接下來,計數。

有一種或多或少的標準方法來計算容器中的某些東西或由輸入給出,然后可能會另外獲取并顯示其排名。所以,按出現頻率排序。

對于計數部分,我們可以使用關聯容器,如 astd::map或 a std::unordered_map在這里,我們將“鍵”(在本例中為“擴展”)與計數和值相關聯,在本例中為特定“擴展”的計數。

幸運的是,基本上選擇這種方法的原因是兩個地圖都有一個非常好的 index operator[]這將查找給定的鍵,如果找到,則回傳對計數的參考。如果未找到,則它將使用鍵(“擴展名”)創建一個新條目并回傳對新條目的參考。因此,在這兩種情況下,我們都將獲得對用于計數的值的參考。然后我們可以簡單地寫:

std::unordered_map<std::string, int> counter{};
counter[extension]  ;

這看起來非常直觀。

完成此操作后,您已經有了頻率表。要么按鍵(單詞)排序,要么使用 astd::map或 unsorted,但使用 a可以更快地訪問std::unordered_map

在您的情況下,您只對計數感興趣, astd::unordered_map是可取的,因為不需要std::map按其鍵對 a 中資料進行排序,以后也不使用此排序。


Then, maybe you want to sort according to the frequency/count. if you do not want to do that, then skip the following:

Sorting of maps by their value is infortunately not possible. Because a major property of a the map - container family is their reference to a key and not a value or count.

Therefore we need to use a second container, like a std::vector, or such, which we then can sort using std::sort for any given predicate, or, we can copy the values into a container, like a std::multiset that implicitly orders its elements. And because this is just a one liner, this is the recommended solution.

Additionally, because writing all these long names for the std containers, we create alias names, with the using keyword.

After we have the rank of the words, so, the list of words sorted by its count, we can use iterators and loops to access the data and output them.


Because you want to read from a file, I would like to give also an additional information regarding opening an closing a file (a stream).

If you read about the ifstream then you will see that is has a constructor, which takes a filename as input and a destructor, which will automatically close the file for you. File opening via the constructor will return a file stream variable which has a state. This is, by the way, true for any stream.

The background is, that its bool-operator is overwritten and will return the state of the stream. Also the not-operator ! is overwritten and can be used. Because of those overwritten operators you can write something like if (filestream) to see, if a file could be opened.

Additionally, since C 17, we have an extended if-statement, where you can use an initializer list in front of the conditions. This is important because it allows us to define a variable, that will be checked later, but with a scope limited to the if compound statement. Which in most cases is very much recommended. Example:

// Open a file and check, if it could be opened
if (std::ifstream infile("file.txt"); infile) {

   // ....   Do things fith file stream

} // Here the file will be closed automatically by the destructor

Much better than unessary open and close statements.


And now, after we thought about the design, now we can start to write code. Not before.

So, we will get now:

#include <iostream>
#include <fstream>
#include <string>
#include <filesystem>
#include <unordered_map>
#include <set>
#include <type_traits>
#include <utility>

// ------------------------------------------------------------
// Create aliases. Save typing work and make code more readable
using Pair = std::pair<std::string, unsigned int>;

// Standard approach for counter
using Counter = std::unordered_map<Pair::first_type, Pair::second_type>;

// Sorted values will be stored in a multiset
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using Sorter = std::multiset<Pair, Comp>;

// Namespace alias
namespace fs = std::filesystem;
// ------------------------------------------------------------


int main() {

    // Open the source file and check, if it could be opened
    if (std::ifstream inFileStream{ "r:\\file.txt" }; inFileStream) {

        // Here we will count the extensions of the file names
        Counter counter{};

        // Read source file strings and count the extensions
        std::string line{};
        // Read all lines from file
        while (std::getline(inFileStream, line))

            // Get extensions and count them
            counter[ fs::path{ line }.extension().string() ]  ;

        // Show result to the user. 
        for (const Pair& p : counter) std::cout << p.first << " --> " << p.second << '\n';

    } // File will be closed here
    else {
        // file could not be opened
        std::cerr << "\n\n*** Error: Input file could not be opened\n\n";
    }
}

With only 8 statements in function main, we can do all the needed task, inclusive all kind of path formats and error handling.

There is more optimization possible.

As I mentioned, it is always a good concept to have a narrow scope for variable. In the above code, we can see the variable "line" is defined in the outer scope of the while loop. That is not necessary. And because we a for and a while loop are basically the same, we can better use a for loop, because it has an initializer part.

Instead of

std::string line{};
        // Read all lines from file
        while (std::getline(inFileStream, line))

we can write

        for  (std::string line{};std::getline(inFileStream, line);  )

We could even exagerate a little bit and do the counting in the iteration expression part of the for-loop. And do the whole reading and counting in just one for statement

        for (std::string line{}; std::getline(inFileStream, line); counter[fs::path{ line }.extension().string()]  )
            ;

So, do the complete reading of the file and the complete counting of all kinds of extensions in one statement in one line of code. Wow!

But readability is a little bit lower and we will not use that.


In the output statement, we could do some more readable stuff. Basically Pair and .first and .second is not that nice and understandable. C has also a solution for that. It is called structured binding.

With all the above, we come now to the final implementation, including output sorted by the frequency:

#include <iostream>
#include <fstream>
#include <string>
#include <filesystem>
#include <unordered_map>
#include <set>
#include <type_traits>
#include <utility>

// ------------------------------------------------------------
// Create aliases. Save typing work and make code more readable
using Pair = std::pair<std::string, unsigned int>;

// Standard approach for counter
using Counter = std::unordered_map<Pair::first_type, Pair::second_type>;

// Sorted values will be stored in a multiset
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using Sorter = std::multiset<Pair, Comp>;

// Namespace alias
namespace fs = std::filesystem;
// ------------------------------------------------------------


int main() {

    // Open the source file and check, if it could be opened
    if (std::ifstream inFileStream{ "r:\\file.txt" }; inFileStream) {

        // Here we will count the extensions of the file names
        Counter counter{};

        // Read all lines from file
        for (std::string line{}; std::getline(inFileStream, line); )

            // Get extensions and count them
            counter[ fs::path{ line }.extension().string() ]  ;

        Sorter sorter(counter.begin(), counter.end());

        // Show result to the user. 
        for (const auto& [extension, count] : sorter) std::cout << extension << " --> " << count << '\n';

    } // File will be closed here
    else {
        // file could not be opened
        std::cerr << "\n\n*** Error: Input file could not be opened\n\n";
    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/350339.html

標籤:C 文件

上一篇:Linux:僅允許2個用戶(共3個)訪問特定檔案夾

下一篇:C從文本檔案中讀取數字

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more