我正在寻找一个简单的例子,介绍如何在C语言中使用跨平台函数将一个文件从一个目录复制到另一个目录。程序应该只使用C语言本身的原生函数。
这是一个简单未经测试的C程序,可以完成你所需的功能:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argn, char * argv[]) {
int src_fd, dst_fd, n, err;
unsigned char buffer[4096];
char * src_path, dst_path;
// Assume that the program takes two arguments the source path followed
// by the destination path.
if (argn != 3) {
printf("Wrong argument count.\n");
exit(1);
}
src_path = argv[1];
dst_path = argv[2];
src_fd = open(src_path, O_RDONLY);
dst_fd = open(dst_path, O_CREAT | O_WRONLY);
while (1) {
err = read(src_fd, buffer, 4096);
if (err == -1) {
printf("Error reading file.\n");
exit(1);
}
n = err;
if (n == 0) break;
err = write(dst_fd, buffer, n);
if (err == -1) {
printf("Error writing to file.\n");
exit(1);
}
}
close(src_fd);
close(dst_fd);
}
open source file read-only
create destination file for write
while there's still data in source file
read data from source file
write it to destination file
close both files
我相信你能做到!
使用dirent.h正确复制文件的C++代码如下。请注意,dirent.h是Linux的一部分,但不包括在Windows中。在Windows上,请查看此处。
对于Windows Visual C++:
// CopyAll_Windows.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<stdio.h>
#include"dirent.h" //Copy dirent.h to folder where stdafx.h is and add to project
#include<errno.h>
#include<sys/stat.h>
#include <iostream>
#define MAX 1024
#define MAX_FILE_NAME_LEN 256
using namespace std;
int main()
{
string homedir = "C:\\Users\\Tom\\Documents";
cerr << endl << "Home = " << homedir.c_str() << endl;
string SrcPath = homedir + "\\Source 1";
string DestPath = homedir + "\\Dest 1\\Dest 1";
string DestPath_mkdir = "\"" + DestPath + "\"";
string command = "mkdir " + DestPath_mkdir;
cerr << endl << "Command = " << command.c_str() << endl << endl;
system(command.c_str());
const char *arSrcPath = SrcPath.c_str();
const char *arDestPath = DestPath.c_str();
struct dirent* spnDirPtr; /* struct dirent to store all files*/
DIR* pnWriteDir = NULL; /*DIR Pointer to open Dir*/
pnWriteDir = opendir(arDestPath);
if (!pnWriteDir)
cerr << endl << "ERROR! Write Directory can not be open" << endl;
DIR* pnReadDir = NULL; /*DIR Pointer to open Dir*/
pnReadDir = opendir(arSrcPath);
if (!pnReadDir || !pnWriteDir)
cerr << endl << "ERROR! Read or Write Directory can not be open" << endl << endl;
else
{
int nErrNo = 0;
while ((spnDirPtr = readdir(pnReadDir)) != NULL)
{
char readPath[MAX_FILE_NAME_LEN] = { 0 };
memset(readPath, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "stat" call
_snprintf_s(readPath, MAX_FILE_NAME_LEN, _TRUNCATE, "%s/%s", arSrcPath, spnDirPtr->d_name);
struct stat st_buf;
stat(readPath, &st_buf);
if (S_ISDIR(st_buf.st_mode))
{
cerr << endl << "Reading directory here..." << endl;
continue;
}
else if (S_ISREG(st_buf.st_mode))
{
if (nErrNo == 0)
nErrNo = errno;
cerr << endl << "Now reading and writing file " << spnDirPtr->d_name << endl;
char strSrcFileName[MAX_FILE_NAME_LEN] = { 0 };
memset(strSrcFileName, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "pnReadFile"
_snprintf_s(strSrcFileName, MAX_FILE_NAME_LEN, _TRUNCATE, "%s/%s", arSrcPath, spnDirPtr->d_name);
FILE* pnReadFile;
errno_t err_read;
if ((err_read = fopen_s(&pnReadFile, strSrcFileName, "r")) == 0)
{
cerr << endl << "Now reading file " << strSrcFileName << endl;
char strDestFileName[MAX_FILE_NAME_LEN] = { 0 };
memset(strDestFileName, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "pnWriteFile"
_snprintf_s(strDestFileName, MAX_FILE_NAME_LEN, _TRUNCATE, "%s/%s", arDestPath, spnDirPtr->d_name);
FILE* pnWriteFile; /*File Pointer to write in file*/
errno_t err_write;
if ((err_write = fopen_s(&pnWriteFile, strDestFileName, "w")) == 0)
{
cerr << endl << "Now writing file " << strDestFileName << endl;
char buffer[MAX] = { 0 }; /*Buffer to store files content*/
while (fgets(buffer, MAX, pnReadFile))
{
fputs(buffer, pnWriteFile);
}
fclose(pnWriteFile);
}
else
{
cerr << endl << "Error! Unable to open file for writing " << strDestFileName << endl;
}
fclose(pnReadFile);
}
else
{
cerr << endl << "ERROR! File Could not be open for reading" << endl;
}
}
}
if (nErrNo != errno)
cerr << endl << "ERROR Occurred!" << endl;
else
cerr << endl << "Process Completed" << endl << endl;
}
closedir(pnReadDir);
closedir(pnWriteDir);
return 0;
}
针对Linux Eclipse C++:
// CopyAll_linux.cpp : Defines the entry point for the console application.
//
//#include "stdafx.h"
#include<stdio.h>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<dirent.h>
#include<errno.h>
#include<sys/stat.h>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#define MAX 1024
#define MAX_FILE_NAME_LEN 256
using namespace std;
int main()
{
const char *homedir;
if ((homedir = getenv("HOME")) == NULL) {
homedir = getpwuid(getuid())->pw_dir;
}
cerr << endl << "Home = " << homedir << endl;
string hd(homedir);
string SrcPath = hd + "/Source 1";
string DestPath = hd + "/Dest 1/Dest 1";
string DestPath_mkdir = "\"" + DestPath + "\"";
string command = "mkdir -p " + DestPath_mkdir;
cerr << endl << "Command = " << command.c_str() << endl << endl;
system(command.c_str());
const char *arSrcPath = SrcPath.c_str();
const char *arDestPath = DestPath.c_str();
struct dirent* spnDirPtr; /* struct dirent to store all files*/
DIR* pnWriteDir = NULL; /*DIR Pointer to open Dir*/
pnWriteDir = opendir(arDestPath);
if (!pnWriteDir)
cerr << endl << "ERROR! Write Directory can not be open" << endl;
DIR* pnReadDir = NULL; /*DIR Pointer to open Dir*/
pnReadDir = opendir(arSrcPath);
if (!pnReadDir || !pnWriteDir)
cerr << endl <<"ERROR! Read or Write Directory can not be open" << endl << endl;
else
{
int nErrNo = 0;
while ((spnDirPtr = readdir(pnReadDir)) != NULL)
{
char readPath[MAX_FILE_NAME_LEN] = { 0 };
memset(readPath, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "stat" call
snprintf(readPath, MAX_FILE_NAME_LEN, "%s/%s", arSrcPath, spnDirPtr->d_name);
struct stat st_buf;
stat(readPath, &st_buf);
if (S_ISDIR(st_buf.st_mode))
{
cerr << endl << "Reading directory here..." << endl;
continue;
}
else if (S_ISREG(st_buf.st_mode))
{
if (nErrNo == 0)
nErrNo = errno;
cerr << endl << "Now reading and writing file "<< spnDirPtr->d_name << endl;
char strSrcFileName[MAX_FILE_NAME_LEN] = { 0 };
memset(strSrcFileName, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "pnReadFile"
snprintf(strSrcFileName, MAX_FILE_NAME_LEN, "%s/%s", arSrcPath, spnDirPtr->d_name);
FILE* pnReadFile;
pnReadFile = fopen(strSrcFileName, "r");
if (pnReadFile == NULL)
cerr << endl << "Null pointer on read file ..." << endl;
if (pnReadFile)
{
cerr << endl << "Now reading file " << strSrcFileName << endl;
char strDestFileName[MAX_FILE_NAME_LEN] = { 0 };
memset(strDestFileName, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "pnWriteFile"
snprintf(strDestFileName, MAX_FILE_NAME_LEN, "%s/%s", arDestPath, spnDirPtr->d_name);
FILE* pnWriteFile = fopen(strDestFileName, "w"); /*File Pointer to write in file*/
if (pnWriteFile)
{
cerr << endl << "Now writing file " << strDestFileName << endl;
char buffer[MAX] = { 0 }; /*Buffer to store files content*/
while (fgets(buffer, MAX, pnReadFile))
{
fputs(buffer, pnWriteFile);
}
fclose(pnWriteFile);
}
else
{
cerr << endl << "Error! Unable to open file for writing " << strDestFileName << endl;
}
fclose(pnReadFile);
}
else
{
cerr << endl << "ERROR! File Could not be open for reading" << endl;
}
}
}
if (nErrNo != errno)
cerr << endl << "ERROR Occurred!" << endl;
else
cerr << endl << "Process Completed" << endl << endl;
}
closedir(pnReadDir);
closedir(pnWriteDir);
return 0;
}
Visual Studio C++ dll:
// copy_all_dll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include<stdio.h>
#include"dirent.h" //Copy dirent.h to folder where stdafx.h is and add to project
#include<errno.h>
#include<sys/stat.h>
#include <iostream>
#define MAX 1024
#define MAX_FILE_NAME_LEN 256
using namespace std;
BOOL DirectoryExists(const char* dirName);
extern "C" __declspec(dllexport) char* copy_combos_all(char *source, char *dest)
{
char *pnError = "";
BOOL dest_exists = DirectoryExists(dest);
if (!dest_exists)
{
string DestPath(dest);
DestPath = "\"" + DestPath + "\"";
string command = "mkdir " + DestPath;
system(command.c_str());
}
const char *arSrcPath = source;
const char *arDestPath = dest;
struct dirent* spnDirPtr; /* struct dirent to store all files*/
DIR* pnWriteDir = NULL; /*DIR Pointer to open Dir*/
pnWriteDir = opendir(arDestPath);
if (!pnWriteDir)
{
pnError = "ERROR! Write Directory can not be open";
return pnError;
}
DIR* pnReadDir = NULL; /*DIR Pointer to open Dir*/
pnReadDir = opendir(arSrcPath);
if (!pnReadDir)
{
pnError = "ERROR! Read Directory can not be open";
if (pnWriteDir)
{
closedir(pnWriteDir);
}
return pnError;
}
else
{
int nErrNo = 0;
while ((spnDirPtr = readdir(pnReadDir)) != NULL)
{
char readPath[MAX_FILE_NAME_LEN] = { 0 };
memset(readPath, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "stat" call
_snprintf_s(readPath, MAX_FILE_NAME_LEN, _TRUNCATE, "%s/%s", arSrcPath, spnDirPtr->d_name);
struct stat st_buf;
stat(readPath, &st_buf);
if (S_ISDIR(st_buf.st_mode))
{
continue;
}
else if (S_ISREG(st_buf.st_mode))
{
if (nErrNo == 0)
nErrNo = errno;
char strSrcFileName[MAX_FILE_NAME_LEN] = { 0 };
memset(strSrcFileName, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "pnReadFile"
_snprintf_s(strSrcFileName, MAX_FILE_NAME_LEN, _TRUNCATE, "%s/%s", arSrcPath, spnDirPtr->d_name);
FILE* pnReadFile;
errno_t err_read;
if ((err_read = fopen_s(&pnReadFile, strSrcFileName, "r")) == 0)
{
char strDestFileName[MAX_FILE_NAME_LEN] = { 0 };
memset(strDestFileName, 0, MAX_FILE_NAME_LEN);
// Following line needed to get real path for "pnWriteFile"
_snprintf_s(strDestFileName, MAX_FILE_NAME_LEN, _TRUNCATE, "%s/%s", arDestPath, spnDirPtr->d_name);
FILE* pnWriteFile;
errno_t err_write;
if ((err_write = fopen_s(&pnWriteFile, strDestFileName, "w")) == 0) /*File Pointer to write in file*/
{
char buffer[MAX] = { 0 }; /*Buffer to store files content*/
while (fgets(buffer, MAX, pnReadFile))
{
fputs(buffer, pnWriteFile);
}
fclose(pnWriteFile);
}
else
{
pnError = "Error! Unable to open file for writing ";
return pnError;
}
fclose(pnReadFile);
}
else
{
pnError = "ERROR! File Could not be open for reading";
return pnError;
}
}
}
if (nErrNo != errno)
{
pnError = "ERROR Occurred!";
}
else
{
pnError = "Process Completed";
}
}
if (pnReadDir)
{
closedir(pnReadDir);
}
if (pnWriteDir)
{
closedir(pnWriteDir);
}
return pnError;
}
BOOL DirectoryExists(const char* dirName) {
DWORD attribs = ::GetFileAttributesA(dirName);
if (attribs == INVALID_FILE_ATTRIBUTES) {
return false;
}
return (attribs & FILE_ATTRIBUTE_DIRECTORY);
}
对于dll,您可以按照以下方式调用:
VB.Net:
<DllImport("copy_all.dll", CallingConvention:=CallingConvention.Cdecl)>
Public Shared Function copy_all(source As String, dest As String) As StringBuilder
End Function
Sub copyAll()
Dim source, dest, homedir As String
homedir = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
source = homedir & "\Source"
dest = homedir & "\Dest"
If Not My.Computer.FileSystem.DirectoryExists(dest) Then
My.Computer.FileSystem.CreateDirectory(dest)
End If
Dim errorMessage As String
errorMessage = ""
Dim sb As New StringBuilder()
sb = copy_all(source, dest)
errorMessage = sb.ToString
If (errorMessage <> "") Then
MessageBox.Show(errorMessage)
End If
End Sub
[DllImport("copy_all.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr copy_all(string source, string dest);
public void copyAll()
{
string homedir = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string source = homedir + "\\Source";
string dest = homedir + "\\Dest";
string error = "";
if (!Directory.Exists(dest))
Directory.CreateDirectory(dest);
IntPtr ptr = copy_all(source, dest);
error = Marshal.PtrToStringAnsi(ptr);
if (error != "")
MessageBox.Show(error);
}
@Mu Qiao提到了boost::filesystem
。具体来说,您需要寻找copy_file
的示例,但您也可以复制目录。
如果您对异步I/O感兴趣,我的印象是boost::asio
有有趣的实现,利用平台能力让您在等待磁盘时使用CPU,就像网络一样:
(注意:最近我一直在想到asio库,但我必须声明我没有在项目中使用过它,也不太清楚它的限制是什么。所以请谨慎考虑我的提及。)
如果您愿意购买,总是因为口味和需求而异,还有其他提供此类功能的跨平台库。我个人喜欢Qt,有很多原因,它确实提供了一个QFile::copy
方法:
另一种选择是这样的:
#ifdef SOME_OS
#define COPY_STR "copy %s %s" // some sort of OS-specific syntax
#elif defined SOME_OTHER_OS
#define COPY_STR "%s cpy %s" // some sort of OS-specific syntax
#else
#error "error text"
#endif
...
#include <stdio.h> //sprintf()
#include <stdlib.h> //system()
char copy_str[LARGE_ENOUGH];
char* source;
char* dest;
...
sprintf (copy_str, COPY_STR, source, dest);
system (copy_str);
source
为"foo.txt bar.txt"
和一个dest
为"& del *.*"
的命令...&符号将它们链接在一起,变成"copy foo.txt bar.txt & del *.*"
。永远记住Bobby Tables!!!http://xkcd.com/327/ - HostileFork says dont trust SEboost::filesystem::copy_file
这样的函数不受此类担忧。我之所以提到Windows,是因为你的第一个字符串示例是COPY_STR "copy %s %s"
(而不是例如COPY_STR "cp %s %s"
)。如果你在任何操作系统中使用这类技术时传递了一个来自程序之外的字符串,同样的问题也可能会出现。消毒成为一个问题,而且通常是一个非常严重的问题。 - HostileFork says dont trust SE我对@te7的答案进行了一些更改,以在MAC上仅从一个文件夹复制一个文件到另一个文件夹。我尝试修改他的代码以仅复制一个文件,但它只部分地将文件写入目标。因此,我使用不同的代码进行文件读/写操作。
void copyFile(string srcDirPath, string destDirPath, string fileName)
{
string command = "mkdir -p " + destDirPath;
cerr << endl << "Command = " << command.c_str() << endl << endl;
system(command.c_str());
DIR* pnWriteDir = NULL; /*DIR Pointer to open Dir*/
pnWriteDir = opendir(destDirPath.c_str());
if (!pnWriteDir)
cerr << endl << "ERROR! Write Directory can not be open" << endl;
DIR* pnReadDir = NULL; /*DIR Pointer to open Dir*/
pnReadDir = opendir(srcDirPath.c_str());
if (!pnReadDir || !pnWriteDir)
cerr << endl <<"ERROR! Read or Write Directory can not be open" << endl << endl;
else
{
string srcFilePath = srcDirPath + fileName;
const char * strSrcFileName = srcFilePath.c_str();
fstream in, out;
in.open(strSrcFileName, fstream::in|fstream::binary);
if (in.is_open()) {
cerr << endl << "Now reading file " << strSrcFileName << endl;
string destFilePath = destDirPath + fileName;
const char * strDestFileName = destFilePath.c_str();
out.open(strDestFileName, fstream::out);
char tmp;
while(in.read(&tmp, 1))
{
out.write(&tmp, 1);
}
out.close();
in.close();
}
else
cerr << endl << "ERROR! File Could not be open for reading" << endl;
}
closedir(pnReadDir);
closedir(pnWriteDir);
}
/*
*
* Module : Copy Multiple from Src dir to Dest dir
* Author : Mohd Asif
* Date : 12-March-2013
* Description : This code will copy all the files from Src dir to Dest Dir
* instead of onother directory inside src dir
* */
#include<stdio.h>
#include<stdio.h>
#include<dirent.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/stat.h>
#define MAX 1024
int main()
{
char arSrcPath[] = "/home/mpe4/Src"; /*Source directory path*/
char arDestPath[] = "/home/mpe4/Dest"; /*dest directory path*/
struct dirent* spnDirPtr; /* struct dirent to store all files*/
DIR* pnOpenDir = NULL; /*DIR Pointer to open Dir*/
DIR* pnReadDir = NULL; /*DIR POinter to read directory*/
pnOpenDir = opendir(arSrcPath);
if(!pnOpenDir)
printf("\n ERROR! Directory can not be open");
else
{
int nErrNo = 0;
while(spnDirPtr = readdir(pnOpenDir))
{
if(nErrNo == 0)
nErrNo = errno;
printf("\n Now writing %s file...",spnDirPtr->d_name);
printf("\n dest file name = %s/%s\n", arDestPath, spnDirPtr->d_name);
struct stat st_buf;
stat(spnDirPtr->d_name, &st_buf);
if (S_ISDIR (st_buf.st_mode))
{
continue;
}
else if (S_ISREG (st_buf.st_mode))
{
FILE* pnReadFile = fopen(spnDirPtr->d_name,"r");
if(pnReadFile)
{
printf("\n Now reading %s file...",spnDirPtr->d_name);
char strDestFileName[MAX] = {0};
sprintf(strDestFileName, "%s/%s", arDestPath, spnDirPtr->d_name);
printf("\n dest file name = %s\n", strDestFileName);
FILE* pnWriteFile = fopen(strDestFileName, "w"); /*File Pointer to write in file*/
if(pnWriteFile)
{
char buffer[MAX] = {0}; /*Buffer to store files content*/
while(fgets(buffer, MAX, pnReadFile))
{
fputs(buffer, pnWriteFile);
}
fclose(pnWriteFile);
}
else
{
printf("\n Unable to open file %s", strDestFileName);
}
fclose(pnReadFile);
}
else
{
printf ("\nERROR! File Could not be open for reading");
}
}
}
if(nErrNo != errno)
printf ("\nERROR Occurred!\n");
else
printf ("\nProcess Completed\n");
}
closedir(pnOpenDir);
return 0;
}
#ifdef
、#else
和#endif
这些预处理块来调用与平台相关的函数,并让编译器决定调用哪一个。 - Stan