rainit2006 / C-Program

C# Program knowledge
0 stars 0 forks source link

File operation #1

Open rainit2006 opened 7 years ago

rainit2006 commented 7 years ago

fstream 是C++标准库提供的函数。但是它不能支持unicode。 也就是如果文件名或路径里包含unicode字符那么它的处理会失败。

关于异常处理: In C++ iostreams do not throw exeptions by default. What you need is

ifstream myfile("test.txt");

if(myfile) {
   // We have one
}
else {
   // we dont
}

关于close处理: ファイルストリームクラスの場合は、デストラクタが自動的に行ってくれます。 もし、明示的なクローズが必要であれば、closeメンバ関数を呼び出します。 ifs.close();

rainit2006 commented 7 years ago

写log到文件


StreamWriter writer = new StreamWriter(@"Log.txt", true);
writer.WriteLine("xxxxxx" + DateTime.Now.ToString("h:mm:ss tt"));
writer.Close();

或者写一个通用函数

        private const string LOG_FILEPATH = @"xxxxxx\xxxxx.log";
        public static void WriteCodeToLog(string logText)
        {
            try
            {
                StringBuilder dataPath = new StringBuilder();
                dataPath.Append(GetPathById(xxxxGUIDxxxxx));
                dataPath.Append(LOG_FILEPATH);

                if (File.Exists(dataPath.ToString()) && !string.IsNullOrEmpty(logText))
                {
                    using (StreamWriter sw = File.AppendText(dataPath.ToString()))
                    {
                        StringBuilder logBuffer = new StringBuilder();
                        logBuffer.AppendLine(
                            string.Format("[{0}]::{1}",
                            DateTime.Now,
                            logText));

                        sw.Write(logBuffer.ToString());
                        sw.Flush();
                        sw.Close();
                    }
                }
            }
            catch
            {
            }
        }
rainit2006 commented 6 years ago

从Binary文件里1byte 单位地 读取数据

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <cstring>
#include <fstream>

using namespace std;

int main()
{

    ifstream file("../TOKYO_PL_1-1000_2.ly5", std::ios_base::in | std::ios_base::binary);
    if (!file.is_open())
    {
        cout << "Error opening file"; 
        exit(1);
    }

    //unsigned char x;
    char x;
    int i = 0;
    while (!file.eof() && (i < 20))  //本demo读取20个byte的数据
    {
        //file.seekg(sizeof(unsigned char)* i);
        file >> x;
        printf(", %#x, %#x\n", x, (unsigned char)x);
        i++;
    }
    return 0;
}

这样读取binary文件有一个问题 : 0D(r)这样的文字会被视为换行符而不会被读取。 想解决这个问题,利用ifstream.get()函数。

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <cstring>
#include <fstream>

using namespace std;

int main()
{

    ifstream file("../TOKYO_PL_1-1000_2.ly5", std::ios_base::in | std::ios_base::binary);
    if (!file.is_open())
    {
        cout << "Error opening file"; 
        exit(1);
    }

    char x;
    int i = 0;
    while (!file.eof() && (i < 20))
    {
        file.get(x);
        printf(", %#x, %#x\n", x, (unsigned char)x); //char是有符号的,对于0xFx的文字会视为负数。
        for (int j = 7; 0 <= j; j--)
            printf("%d\n", (x >> j) & 0x01); //按bit显示。
        i++;
    }
    return 0;
}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーー 一行一行地读取文件 利用include里的getline函数

string x;
getline(file, x);
rainit2006 commented 6 years ago

getting file names without extensions Path.GetFileNameWithoutExtension https://msdn.microsoft.com/ja-jp/library/system.io.path.getfilenamewithoutextension(v=vs.110).aspx Ex.

foreach (FileInfo fi in smFiles)
{
    builder.Append(Path.GetFileNameWithoutExtension(fi.Name));
    builder.Append(", ");
}

File writing operation File.AppendAllText 创建文件,并追加内容 File.WriteAllText 创建文件,覆盖写入内容

换行符: environment.NewLine e.url.toString() + environment.NewLine

rainit2006 commented 6 years ago

Which is fastest: read, fread, ifstream or mmap? https://lemire.me/blog/2012/06/26/which-is-fastest-read-fread-ifstream-or-mmap/

利用内存映射读取大文件 http://blog.csdn.net/kuaile123/article/details/11149751 内存映射的优势还是在于大文件。 fstream.open() 时,由于文件太大,IO一次读不了所有的数据,需要多次IO操作。 而内存映射,并不是将文件加载到内存。内存映射首先申请一段地址空间,并映射到物理存储器,而这里的物理存储器就是文件所在的磁盘,类似虚拟内存(pagefile); 当有需要时,程序不需要先把它加到内存,而是直接从磁盘读取。这样就减少了IO操作。

rainit2006 commented 6 years ago

查找目录里的所有文件

下面例子是把目录下的文件列出来。

#include <windows.h>

void read_directory(const std::string& name, stringvec& v)
{
    std::string pattern(name);
    pattern.append("\\*");
    WIN32_FIND_DATA data;
    HANDLE hFind;
    if ((hFind = FindFirstFile(pattern.c_str(), &data)) != INVALID_HANDLE_VALUE) {
        do {
            v.push_back(data.cFileName);
        } while (FindNextFile(hFind, &data) != 0);
        FindClose(hFind);
    }
}
rainit2006 commented 6 years ago

判断是文件还是目录 Call GetFileAttributes, and check for the FILE_ATTRIBUTE_DIRECTORY attribute.

BOOL isDirectory(LPCTSTR szPath)
{
  DWORD dwAttrib = GetFileAttributes(szPath);

  return (dwAttrib != INVALID_FILE_ATTRIBUTES && 
         (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}

GetFileAttributes API for C++ https://msdn.microsoft.com/en-us/library/aa364944(VS.85).aspx

rainit2006 commented 6 years ago
rainit2006 commented 6 years ago

ifstream打开含中文路径名文件失败的原因 http://www.cnblogs.com/kevinGaoblog/archive/2012/07/20/2601236.html

在VS2008的“Property Pages”属性页中,选择“Configuration Properties”-->“General”,可以看到当前使用的字符集是“Multi-Byte Character Set”,也就是说程序中使用的是多字节字符集。 从设置选项中可以看到,工程中使用的字符集可设置为“Multi-Byte Character Set”或“Unicode Character Set”,其中“Multi-Byte Character Set”表示使用ANSI编码方式,“Unicode Character Set”表示使用UNICODE编码方式。

那么这两种编码方式有什么样的区别呢? (1)传统的计算机使用ANSI编码,在ANSI编码模式下,英文字符都用1个字节表示,而某些其它国家的文字(如汉字、日文),无法用单个字节来表示,ANSI便采用多个字节来表示这些字符(汉字是2个字节)。

(2)UNICODE包含UTF-8、UTF-16、UTF-32等多种编码方案(目前windows一般使用UTF-16)。拿UTF-16来说,规定所有字符都使用2个字节表示(不论英文字母还是汉字),对于超出2个字节范围的字符采用代理(采用4个字节表示)。 UNICODE相比ANSI有很多方面的优势(优势体现在哪?),微软非常提倡使用UNICODE编码方式,在MS较新版本的系统中都是采用UNICODE编码的。因此,即便我们在自己写的程序中使用了ANSI编码,系统会将其转换为UNICODE再对其进行处理。

接下来我们说一下ifstream。在调用ifstream的open方法时,系统内部调用mbstowcs_s进行文件名转换(mbstowcs_s函数的作用是把多字节字符转化为宽字符),需要注意的是,该函数的调用结果依赖于程序的本地化设置(什么是本地化设置?)。而本地化设置可以通过setlocale函数来设置,譬如:setlocale(LC_ALL, "chinese")表示将程序本身的语言设置为中文,而程序启动时默认设置为LC_ALL="C"。在使用mbstowcs_s进行字符串转换时,只有当LC_ALL="chinese"时,含中文的字符串才能正确的转换成其对应的宽字节字符,否则(在LC_ALL="C"时),汉字会被看成2个单字节的字符,然后再转换成宽字节的字符,这样转换的结果显然是错误的!这就是ifstream打开含中文路径的文件失败的原因,因为"d://测试.txt"转换后得到错误的路径,因此文件打不开!

解决方法如下:

/*方法1,
  使用STL中的locale类的静态方法指定全局locale                   
  使用该方法以后,cout可能不能正常输出中文,十分蹊跷                    
  我发现了勉强解决的方法:不要在还原区域设定前用cout或wcout输出中文,
  否则后果就是还原区域设定后无法使用cout wcout输出中文           
  */
  locale::global(locale(""));//将全局区域设为操作系统默认区域
  file.open("d://测试//测试文本.txt");//可以顺利打开文件了
  locale::global(locale("C"));//还原全局区域设定
  cout<<file.rdbuf();
  file.close();
/* 方法2,使用C函数setlocale,不能用cout输出中文的问题解决方法同上 */
  setlocale(LC_ALL,"Chinese-simplified");//设置中文环境
  file.open("c://测试//测试文本3.txt");//可以顺利打开文件了
  setlocale(LC_ALL,"C");//还原
  cout<<file.rdbuf();
  file.close();
rainit2006 commented 6 years ago

CFile类 GetLength(): 获得文件的大小。 比如文件内容需要占用内存228KB。

iRet = cFile.Open( (LPTSTR)filePath.GetBuffer(0) , CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone );
    if ( iRet == 0 ) {
        ASSERT(0);
        vErrLogWrite( FATAL_ERROR , __FILE__ ,__LINE__,cString.GetBuffer(0),0,0);
        return ERROR;
    }
    ulSize = (ulong)cFile.GetLength();
    pcRetAddr = (char *)malloc( ulSize );
    cFile.Read( pcAddr, ulSize );
    cFile.Close();