C++ 使用非ASCII字符打开文件
我正在尝试计算文件的SHA-256。我有下面的代码,当路径有效时给出正确的校验和值,即ASCII。我有以下代码:C++ 使用非ASCII字符打开文件,c++,visual-studio-2010,unicode,C++,Visual Studio 2010,Unicode,我正在尝试计算文件的SHA-256。我有下面的代码,当路径有效时给出正确的校验和值,即ASCII。我有以下代码: #include <openssl\evp.h> #include <sys\stat.h> #include <iostream> #include <string> #include <fstream> #include <cstdio> const int MAX_BUFFER_SIZE = 1024; s
#include <openssl\evp.h>
#include <sys\stat.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
const int MAX_BUFFER_SIZE = 1024;
std::string FileChecksum(std::string, std::string);
long long int GetFileSize(std::string filename)
{
struct _stat64 stat_buf;
int rc = _stat64(filename.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
std::string fname = "D:\\Private\\Test\\asdf.txt"; // Need to support this D:\\Private\\Test\\सर्वज्ञ पन्त.txt
int main()
{
std::string checksum = FileChecksum(fname , "sha256");
std::cout << checksum << std::endl;
return 0;
}
static std::string FileChecksum(std::string file_path, std::string algorithm="sha256")
{
EVP_MD_CTX *mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
int i;
unsigned int md_len;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(algorithm.c_str());
if(!md) {
printf("Unknown message digest %s\n",algorithm);
return "";
}
mdctx = EVP_MD_CTX_create();
std::ifstream readfile(file_path,std::ifstream::binary);
if(!readfile.is_open())
{
std::cout << "COuldnot open file\n";
return "";
}
readfile.seekg(0, std::ios::end);
long long filelen = readfile.tellg();
std::cout << "LEN IS " << filelen << std::endl;
readfile.seekg(0, std::ios::beg);
if(filelen == -1)
{
std::cout << "Return Null \n";
return "";
}
EVP_DigestInit_ex(mdctx, md, NULL);
long long temp_fil = filelen;
while(!readfile.eof() && readfile.is_open() && temp_fil>0)
{
int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
char *buffer = new char[bufferS+1];
buffer[bufferS] = 0;
readfile.read(buffer, bufferS);
EVP_DigestUpdate(mdctx, buffer, bufferS);
temp_fil -= bufferS;
delete[] buffer;
}
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
char str[128] = { 0 };
char *ptr = str;
std::string ret;
for(i = 0; i < md_len; i++)
{
//_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
sprintf(ptr,"%02x", md_value[i]);
ptr += 2;
}
ret = str;
/* Call this once before exit. */
EVP_cleanup();
return ret;
}
#包括
#包括
#包括
#包括
#包括
#包括
const int MAX_BUFFER_SIZE=1024;
std::string文件校验和(std::string,std::string);
长整型GetFileSize(标准::字符串文件名)
{
结构stat64 stat buf;
int rc=_stat64(filename.c_str(),&stat_buf);
返回rc==0?统计数据大小:-1;
}
std::string fname=“D:\\Private\\Test\\asdf.txt”;//需要支持此D:\\Private\\Test\\सर्वज्ञ पन्त.文本
int main()
{
std::string checksum=FileChecksum(fname,“sha256”);
std::coutwchar\u t
不能跨多个平台移植,因为它在某些平台(Windows)上是2字节(UTF-16),但在其他平台(Linux等)上是4字节(UTF-32)。这就是警告您的内容
在您的特定情况下,您只关注Windows,因此使用std::wstring
非常好,因为它使用UTF-16,这与Win32 API在所有地方使用的编码相同。您正在寻找的是Microsoft的\wstat64()
函数,以及接受wchar\t*
文件名的Microsoft非标准std::ifstream
构造函数:
long long int GetFileSize(std::wstring filename)
{
struct _stat64 stat_buf;
int rc = _wstat64(filename.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
也就是说,您的FileChecksum()
函数比它需要的更复杂,如果发生错误,它没有正确清理,它没有验证std::ifstream::read()
是否实际读取了您所请求的字节数(它可以读取更少),并且它误用了std::ifstream::eof()
请尝试类似以下内容:
#include <openssl\evp.h>
#include <sys\stat.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <iomanip>
const int MAX_BUFFER_SIZE = 1024;
std::string FileChecksum(std::wstring file_path, std::string algorithm = "sha256");
std::wstring fname = L"D:\\Private\\Test\\सर्वज्ञ पन्त.txt";
int main()
{
std::string checksum = FileChecksum(fname, "sha256");
std::cout << checksum << std::endl;
return 0;
}
std::string FileChecksum(std::wstring file_path, std::string algorithm)
{
EVP_MD_CTX *mdctx = NULL;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
char buffer[MAX_BUFFER_SIZE];
unsigned int md_len;
std::ostringstream oss;
std::string ret;
std::ifstream readfile(file_path.c_str(), std::ifstream::binary);
if (readfile.fail())
{
std::cout << "Could not open file\n";
goto finished;
}
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(algorithm.c_str());
if (!md) {
std::cout << "Unknown message digest " << algorithm << "\n";
goto cleanup;
}
mdctx = EVP_MD_CTX_create();
if (!mdctx) {
std::cout << "Could not create context for message digest " << algorithm << "\n";
goto cleanup;
}
EVP_DigestInit_ex(mdctx, md, NULL);
do
{
readfile.read(buffer, sizeof(buffer));
if ((readfile.fail()) && (!readfile.eof()))
{
std::cout << "Could not read from file\n";
goto cleanup;
}
EVP_DigestUpdate(mdctx, buffer, readfile.gcount());
}
while (!readfile.eof());
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
for(unsigned int i = 0; i < md_len; i++)
oss << std::hex << std::setw(2) << std::setfill('0') << (int) md_value[i];
ret = oss.str();
cleanup:
if (mdctx) EVP_MD_CTX_destroy(mdctx);
EVP_cleanup();
finished:
return ret;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
const int MAX_BUFFER_SIZE=1024;
std::string FileChecksum(std::wstring file_path,std::string algorithm=“sha256”);
std::wstring fname=L“D:\\Private\\Test\\सर्वज्ञ पन्त.txt”;
int main()
{
std::string checksum=FileChecksum(fname,“sha256”);
std::对于ifstream
,您是否不需要in
。它是“in”区域是的。这是一个愚蠢的错误。这似乎是一个“与接受UTF-16的API相邻的点”,所以std::wstring听起来不错。什么情况下我应该更喜欢std::wstring而不是std::string?吹毛求疵:不要按字符串参数选择算法,使用枚举或类似的东西。do不一定要跟随一段时间。while似乎缺少。我必须这样做使此代码跨平台。该代码应在windows和linux中获取文件的校验和。是的,它在
时丢失了一个,我现在已经修复了它。不幸的是,不同的平台以不同的编码处理不同的文件路径(windows使用UTF-16,*Nix使用UTF-8等),不同的格式,等等。因此,您必须使用#ifdef
语句中包装的一些特定于平台的代码来说明这一点,除非您使用已经为您提供了该功能的第三方库。代码无法计算正确的校验和。在调试器下运行时,代码会将文件数据读入缓冲区,并且如果内容s小于缓冲区的大小,缓冲区中有剩余。例如,由于没有终止字符,所以像sdasÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ
返回缓冲区中的实际字节数,方法是read
。缓冲区中没有剩余传递给EVP\u DigestUpdate()
。至于!
返回true,我忘记了read()
在达到EOF时设置failbit
和eofbit
。我已经更新了代码以说明这一点。代码现在似乎正常工作,但现在计算错误的校验和。它确实支持非ascii路径,但计算的SHA-256是错误的。
#include <openssl\evp.h>
#include <sys\stat.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <iomanip>
const int MAX_BUFFER_SIZE = 1024;
std::string FileChecksum(std::wstring file_path, std::string algorithm = "sha256");
std::wstring fname = L"D:\\Private\\Test\\सर्वज्ञ पन्त.txt";
int main()
{
std::string checksum = FileChecksum(fname, "sha256");
std::cout << checksum << std::endl;
return 0;
}
std::string FileChecksum(std::wstring file_path, std::string algorithm)
{
EVP_MD_CTX *mdctx = NULL;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
char buffer[MAX_BUFFER_SIZE];
unsigned int md_len;
std::ostringstream oss;
std::string ret;
std::ifstream readfile(file_path.c_str(), std::ifstream::binary);
if (readfile.fail())
{
std::cout << "Could not open file\n";
goto finished;
}
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(algorithm.c_str());
if (!md) {
std::cout << "Unknown message digest " << algorithm << "\n";
goto cleanup;
}
mdctx = EVP_MD_CTX_create();
if (!mdctx) {
std::cout << "Could not create context for message digest " << algorithm << "\n";
goto cleanup;
}
EVP_DigestInit_ex(mdctx, md, NULL);
do
{
readfile.read(buffer, sizeof(buffer));
if ((readfile.fail()) && (!readfile.eof()))
{
std::cout << "Could not read from file\n";
goto cleanup;
}
EVP_DigestUpdate(mdctx, buffer, readfile.gcount());
}
while (!readfile.eof());
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
for(unsigned int i = 0; i < md_len; i++)
oss << std::hex << std::setw(2) << std::setfill('0') << (int) md_value[i];
ret = oss.str();
cleanup:
if (mdctx) EVP_MD_CTX_destroy(mdctx);
EVP_cleanup();
finished:
return ret;
}