解决:VS 2005/2008 中 fstream 不能处理带有中文路径的问题

本文介绍了解决在使用C++ STL中的ifstream和ofstream处理包含中文路径的文件时遇到的问题。通过设置locale为系统语言环境,可以成功打开并操作中文路径的文件,同时提供了注意事项避免后续输出问题。

有时候用ifstream或ofstream打开带有中文路径的文件会失败。

解决办法:
1、使用C语言的函数设置为中文运行环境
setlocale(LC_ALL,"Chinese-simplified");

2、使用STL函数设置为系统语言环境
std::locale::global(std::locale(""));

当然选2啦!

 ofstream writefile;

vc中ifstream ofstream不能读取带有中文路径 - 西北捍将 - 西北捍将 string filename=("d:/我的文档/测试.txt");

vc中ifstream ofstream不能读取带有中文路径 - 西北捍将 - 西北捍将     locale loc = locale::global(locale("")); //要打开的文件路径含中文,设置全局locale为本地环境

vc中ifstream ofstream不能读取带有中文路径 - 西北捍将 - 西北捍将     writefile.open(filename.c_str(),ios::out); //打开文件

vc中ifstream ofstream不能读取带有中文路径 - 西北捍将 - 西北捍将     locale::global(loc);//恢复全局locale

用locale对象的name方法可以看到,通过locale("")构造出的locale对象的name为"Chinese_People's Republic of China.936",而原始的locale对象的name为"C",也就是缺省的ANSI_C公约。

注意:如果使用locale loc = locale::global(locale(""))设置全局locale后没有用 locale::global(loc)恢复的话,那么在程序后面的cout语句就不能输出中文了,虽然这时候操作中文文件没有问题,但是这也是很容易让人掉入陷阱的地方,应该值得注意。解决方法:

先将CString 转为char*

CString str=view->m_sFilePath;
   //CString str = "";
   //ofstream 中传的参数不能有汉字,必须转换,一下是其暂缓方法
   str.AppendFormat("cluster%d%d.txt",aMatrix->X_part,aMatrix->Y_part);
   char*   sz   =   str.GetBuffer(str.GetLength());
   locale loc = locale::global(locale(""));
   ofstream ofile(sz);

 

转自:http://anwj336.blog.163.com/blog/static/89415209200991931213190/

----------------------------------------------------------------------------------------------------------------------------------------------------

 

VC 2005中的locale

连续碰到两次和locale相关的问题,一次是ifstream, 一次是boost::format, 做了些实验记录下来:

1. ifstream 的文件名参数其实可以接受char *, 也可以接受wchar_t * 作为参数,如果接受char * 的话,实际上内部也是转换成为wchar_t *,但转换的时候问题就来了,如果此文件名里面有汉字,vc2005就转换不对,这样就打不开文件了。在vc2005中,一开始程序的缺省locale是”C”, 也就是std::locale::classic()返回的,但这个locale下,汉字转换是不正确的,所以,要先用 std::locale::global(std::locale(”"))这样的语句将locale设到系统缺省的。实际上std::locale::global(std::locale(”.936″)) 也是一样的。936就是简体中文的codepage(代码页)。 此时用 locale.name() 打印出来的locale名称为: “Chinese_People’s Republic of China.936″

 

2. 但是一旦locale变为936了,cout 输出中文就又会有问题,碰到中文就会断掉,而且后面的东西再也显示不出来。这可以通过在ifstream打开文件之后,用std::locale::global(std::locale(”C”))再设回缺省locale来解决。

 

3. locale设为936的另一个问题是,boost::format 中 如果输出数字的话,1234会变成1, 234. 这个问题也可以用上面的方法来解决。另外一个方法是可以用format的第二个参数来做,例如std::locale::classic() 或者std::locale(”C”);

 

4. 网上说流输出时候也会将1234变为 1,234,但我直接实验cout << 1234 好像没有问题。看到说碰到这种情况,需要用a.imbue(std::locale(”C”))。

 

5. 如果ifstream直接用wchar_t *的文件名参数,就很简单了,由于不更改locale就可以打开文件,后面的cout输出汉字也没有问题,boost::format也没有问题。所以竭力推荐这种方法 :)

---------------------------------------------------------------------------------------------------------------------------------------------

一. locale
   一个流在初始化时将隐式地使用全局locale, 而初始时候的全局locale就是标准的"C"模式locale::classic()
在VC与中文版xp下, 也是这样。

 

二. 静态函数locale::global(newloc) 可设置newloc为全局locale,并且返回以前的全局locale,可将之保存起来
以后恢复, 随时要记得恢复这点很重要。
   locale newloc(""); //在简体中文xp系统上等价于".936"
   locale& oldloc = locale::global(newloc);
   ...
   locale::global(oldloc);
  
   纯API方式下用
   setlocale(LC_ALL,"C");   
   setlocale(LC_ALL,".936"); 也可以用 setlocale(LC_ALL,   "");

 

三. Bjarne Stroustrup提到用locale::global(x)的时候将同时设置全局locale,但我在VC中混用API
和stl的来设置locale时候有些微小的差别,所以今后要注意最好成对地设置,也就是用API去设置,以后恢复也用
API来做,相应地,用stl类locale去设置,也用同样的类去恢复回来。


转自: http://hi.baidu.com/eith/blog/item/4525a016635f9c5df3de3294.html

题目要求为:编写套接字程序,要求实现一下内容 • 以C/S架构实现文件传输 • 客户端可以选择指定本地需要上传的文件; • 服务端可以更改文件保存路径 • 支持两个以上客户端同时上传文件(即同时打开两个以上的客户端分别进行文件传输) • 要求以C++的形式进行程序设计,不要求图形界面 • 提交实验报告(按课程设计格式进行撰写) server.cpp代码:#define NOMINMAX // 禁用Windows的min/max宏,必须放在头文件前 #include <iostream> #include <string> #include <cstring> #include <thread> #include <vector> #include <fstream> #include <winsock2.h> #include <ws2tcpip.h> #include <filesystem> #include <algorithm> // 用于std::min #include <stdexcept> #pragma comment(lib, "ws2_32.lib") namespace fs = std::filesystem; // 处理单个客户端连接 void handle_client(SOCKET client_socket, const std::string& save_path) { try { // 接收文件名长度 int filename_len; int recv_len = recv(client_socket, (char*)&filename_len, sizeof(filename_len), 0); if (recv_len <= 0) { throw std::runtime_error("接收文件名长度失败"); } filename_len = ntohl(filename_len); // 系统内置函数 // 接收文件名 char* filename_buf = new char[filename_len + 1]; recv_len = recv(client_socket, filename_buf, filename_len, 0); if (recv_len <= 0) { delete[] filename_buf; throw std::runtime_error("接收文件名失败"); } filename_buf[filename_len] = '\0'; std::string filename = filename_buf; delete[] filename_buf; // 接收文件大小 uint64_t file_size; recv_len = recv(client_socket, (char*)&file_size, sizeof(file_size), 0); if (recv_len <= 0) { throw std::runtime_error("接收文件大小失败"); } file_size = ntohll(file_size); // 系统内置函数 std::cout << "\n[客户端连接] 接收文件: " << filename << " (大小: " << file_size << "字节)" << std::endl; // 确保保存目录存在 if (!fs::exists(save_path)) { fs::create_directories(save_path); std::cout << "已创建保存目录: " << save_path << std::endl; } // 构建保存路径(Windows用反斜杠) std::string full_path = save_path + "\\" + filename; std::ofstream file(full_path, std::ios::binary); if (!file.is_open()) { throw std::runtime_error("无法创建文件: " + full_path); } // 接收文件内容 const int BUFFER_SIZE = 4096; char buffer[BUFFER_SIZE]; uint64_t total_received = 0; while (total_received < file_size) { // 计算剩余字节数,显式转换为int避免类型冲突 int remaining = static_cast<int>(file_size - total_received); int bytes_to_read = std::min(BUFFER_SIZE, remaining); // 已解决宏冲突 recv_len = recv(client_socket, buffer, bytes_to_read, 0); if (recv_len <= 0) { throw std::runtime_error("文件接收中断(客户端断开)"); } file.write(buffer, recv_len); total_received += recv_len; // 显示进度(仅在控制台输出) float progress = static_cast<float>(total_received) / file_size * 100; printf("\r接收进度: %.1f%%", progress); // 用printf避免cout的缓冲问题 std::cout.flush(); } std::cout << std::endl; // 进度条后换行 file.close(); std::cout << "文件接收完成: " << full_path << std::endl; } catch (const std::exception& e) { std::cerr << "\n处理客户端出错: " << e.what() << std::endl; } closesocket(client_socket); // 关闭客户端套接字 } int main(int argc, char* argv[]) { // 初始化Winsock WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { std::cerr << "Winsock初始化失败!错误码: " << WSAGetLastError() << std::endl; return 1; } // 默认参数(端口+保存路径) int port = 8888; std::string save_path = "./received_files"; // 解析命令行参数(可选:端口 保存路径) if (argc >= 2) { port = std::stoi(argv[1]); // 例如:server.exe 8888 D:\files } if (argc >= 3) { save_path = argv[2]; } // 创建服务器套接字 SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server_socket == INVALID_SOCKET) { std::cerr << "创建套接字失败!错误码: " << WSAGetLastError() << std::endl; WSACleanup(); return 1; } // 设置端口重用(避免程序重启后端口被占用) int opt = 1; if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)) == SOCKET_ERROR) { std::cerr << "设置端口重用失败!错误码: " << WSAGetLastError() << std::endl; closesocket(server_socket); WSACleanup(); return 1; } // 绑定地址和端口 sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有本地IP server_addr.sin_port = htons(port); if (bind(server_socket, (SOCKADDR*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) { std::cerr << "绑定端口失败!错误码: " << WSAGetLastError() << std::endl; closesocket(server_socket); WSACleanup(); return 1; } // 开始监听(最大等待队列5个) if (listen(server_socket, 5) == SOCKET_ERROR) { std::cerr << "监听失败!错误码: " << WSAGetLastError() << std::endl; closesocket(server_socket); WSACleanup(); return 1; } std::cout << "服务器启动成功!" << std::endl; std::cout << "监听端口: " << port << std::endl; std::cout << "文件保存路径: " << save_path << std::endl; std::cout << "等待客户端连接..." << std::endl; // 管理客户端线程(无需手动join,用detach自动回收) std::vector<std::thread> client_threads; while (true) { // 无限循环接受连接 sockaddr_in client_addr; int client_addr_len = sizeof(client_addr); SOCKET client_socket = accept(server_socket, (SOCKADDR*)&client_addr, &client_addr_len); if (client_socket == INVALID_SOCKET) { std::cerr << "接受连接失败!错误码: " << WSAGetLastError() << std::endl; continue; } // 获取客户端IP char client_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN); std::cout << "\n新客户端连接: " << client_ip << ":" << ntohs(client_addr.sin_port) << std::endl; // 创建线程处理该客户端 client_threads.emplace_back(handle_client, client_socket, save_path); client_threads.back().detach(); } // 理论上不会执行到这里(无限循环) closesocket(server_socket); WSACleanup(); return 0; } client.cpp代码: #define NOMINMAX // 禁用Windows的min/max宏 #include <iostream> #include <string> #include <cstring> #include <fstream> #include <winsock2.h> #include <ws2tcpip.h> #include <filesystem> #include <stdexcept> #pragma comment(lib, "ws2_32.lib") namespace fs = std::filesystem; // 发送文件到服务器 bool send_file(SOCKET socket, const std::string& file_path) { try { // 检查文件是否存在 if (!fs::exists(file_path)) { throw std::runtime_error("文件不存在: " + file_path); } if (!fs::is_regular_file(file_path)) { throw std::runtime_error("不是常规文件: " + file_path); } // 获取文件信息 std::string filename = fs::path(file_path).filename().string(); uint64_t file_size = fs::file_size(file_path); std::cout << "准备发送文件: " << filename << " (大小: " << file_size << "字节)" << std::endl; // 步骤1:发送文件名长度(4字节,网络字节序) int filename_len = static_cast<int>(filename.size()); int net_filename_len = htonl(filename_len); if (send(socket, (char*)&net_filename_len, sizeof(net_filename_len), 0) <= 0) { throw std::runtime_error("发送文件名长度失败"); } // 步骤2:发送文件名(n字节) if (send(socket, filename.c_str(), filename_len, 0) <= 0) { throw std::runtime_error("发送文件名失败"); } // 步骤3:发送文件大小(8字节,网络字节序) uint64_t net_file_size = htonll(file_size); // 系统内置函数 if (send(socket, (char*)&net_file_size, sizeof(net_file_size), 0) <= 0) { throw std::runtime_error("发送文件大小失败"); } // 步骤4:发送文件内容 std::ifstream file(file_path, std::ios::binary); if (!file.is_open()) { throw std::runtime_error("无法打开文件: " + file_path); } const int BUFFER_SIZE = 4096; char buffer[BUFFER_SIZE]; uint64_t total_sent = 0; while (total_sent < file_size) { // 读取文件到缓冲区 file.read(buffer, BUFFER_SIZE); size_t bytes_read = file.gcount(); // 实际读取的字节数 // 发送缓冲区数据 if (send(socket, buffer, bytes_read, 0) <= 0) { throw std::runtime_error("文件发送中断(服务器断开)"); } total_sent += bytes_read; // 显示进度 float progress = static_cast<float>(total_sent) / file_size * 100; printf("\r发送进度: %.1f%%", progress); std::cout.flush(); } std::cout << std::endl; // 进度条后换行 file.close(); std::cout << "文件发送完成!" << std::endl; return true; } catch (const std::exception& e) { std::cerr << "\n发送失败: " << e.what() << std::endl; return false; } } int main(int argc, char* argv[]) { // 初始化Winsock WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { std::cerr << "Winsock初始化失败!错误码: " << WSAGetLastError() << std::endl; return 1; } // 默认参数(服务器IP+端口+文件路径) std::string server_ip = "127.0.0.1"; // 本地测试用 int port = 8888; std::string file_path; // 解析命令行参数(可选:IP 端口 文件路径) if (argc >= 2) { server_ip = argv[1]; // 例如:client.exe 192.168.1.100 8888 C:\test.txt } if (argc >= 3) { port = std::stoi(argv[2]); } if (argc >= 4) { file_path = argv[3]; } // 若未指定文件,手动输入 if (file_path.empty()) { std::cout << "请输入要上传的文件路径: "; std::getline(std::cin, file_path); } // 创建客户端套接字 SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (client_socket == INVALID_SOCKET) { std::cerr << "创建套接字失败!错误码: " << WSAGetLastError() << std::endl; WSACleanup(); return 1; } // 连接服务器 sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); // 转换IP字符串为二进制 if (inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr) <= 0) { std::cerr << "无效的服务器IP: " << server_ip << std::endl; closesocket(client_socket); WSACleanup(); return 1; } // 建立连接 if (connect(client_socket, (SOCKADDR*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) { std::cerr << "连接服务器失败!错误码: " << WSAGetLastError() << std::endl; closesocket(client_socket); WSACleanup(); return 1; } std::cout << "已成功连接到服务器: " << server_ip << ":" << port << std::endl; // 发送文件 send_file(client_socket, file_path); // 清理资源 closesocket(client_socket); WSACleanup(); return 0; } 检查上述代码,找出在程序按要求运行时在client控制台输入位于D盘根目录下的txt文件地址后显示无法查找该文件的原因,并给出解决方案
最新发布
11-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值