generated from zhangwei/Matrixai
526 lines
15 KiB
C++
526 lines
15 KiB
C++
/*
|
|
* Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "FileManager.h"
|
|
#include <ctime>
|
|
#include <string>
|
|
|
|
namespace {
|
|
const int BUFFER_SIZE = 2048;
|
|
#ifndef _WIN32
|
|
const mode_t DEFAULT_FILE_PERMISSION = 0077;
|
|
#endif
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
mode_t SetFileDefaultUmask()
|
|
{
|
|
return umask(DEFAULT_FILE_PERMISSION);
|
|
}
|
|
|
|
mode_t SetFileUmask(mode_t newUmask)
|
|
{
|
|
return umask(newUmask);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Check whether the file exists.
|
|
*
|
|
* @param filePath the file path we want to check
|
|
* @return APP_ERR_OK if file exists, error code otherwise
|
|
*/
|
|
APP_ERROR ExistFile(const std::string &filePath)
|
|
{
|
|
std::string resolvedPath;
|
|
APP_ERROR ret = GetRealPath(filePath, resolvedPath);
|
|
if (ret != APP_ERR_OK) {
|
|
return ret;
|
|
}
|
|
#ifndef _WIN32
|
|
struct stat fileStat = {0};
|
|
if (stat(resolvedPath.c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode)) {
|
|
#else
|
|
DWORD fileStat = GetFileAttributes((LPCSTR)resolvedPath.c_str());
|
|
if ((fileStat == FILE_ATTRIBUTE_ARCHIVE) || (fileStat == FILE_ATTRIBUTE_NORMAL) ||
|
|
(fileStat == FILE_ATTRIBUTE_DIRECTORY)) {
|
|
#endif
|
|
return APP_ERR_OK;
|
|
}
|
|
return APP_ERR_COMM_FAILURE;
|
|
}
|
|
|
|
/**
|
|
* Split the input path string with delimiter
|
|
*
|
|
* @param str path string
|
|
* @param delimiters a set of delimiter
|
|
* @return the vector of splitted path
|
|
*/
|
|
std::vector<std::string> SplitPath(const std::string &str, const std::set<char> delimiters)
|
|
{
|
|
std::vector<std::string> result;
|
|
std::string temp = str;
|
|
auto start = temp.begin();
|
|
auto it = temp.begin();
|
|
for (; it != temp.end(); ++it) {
|
|
if (delimiters.find(*it) != delimiters.end()) {
|
|
if (it != start) {
|
|
result.emplace_back(start, it);
|
|
} else {
|
|
result.emplace_back("");
|
|
}
|
|
start = it + 1;
|
|
}
|
|
}
|
|
result.emplace_back(start, it);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Create a directory
|
|
*
|
|
* @param dirPath the directory we want to create
|
|
* @return APP_ERR_OK if create success, error code otherwise
|
|
*/
|
|
APP_ERROR CreateDir(const std::string &dirPath)
|
|
{
|
|
#ifndef _WIN32
|
|
SetFileDefaultUmask();
|
|
if (dirPath.length() > PATH_MAX) {
|
|
LogError << dirPath << "is larger than " << std::to_string(PATH_MAX) << ".";
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
}
|
|
#else
|
|
if (dirPath.length() > MAX_PATH) {
|
|
LogError << dirPath << "is larger than " << std::to_string(MAX_PATH) << ".";
|
|
}
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
#endif
|
|
|
|
// Check the write authority of directory, if not exist, create it
|
|
int dirExist = access(dirPath.c_str(), W_OK);
|
|
if (-1 == dirExist) {
|
|
#ifdef _WIN32
|
|
if (_mkdir(dirPath.c_str()) == -1) {
|
|
#else
|
|
if (mkdir(dirPath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
|
|
#endif
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
}
|
|
}
|
|
return APP_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* Create directory recursively
|
|
*
|
|
* @param file target directory to create
|
|
*/
|
|
void CreateDirRecursively(const std::string &file)
|
|
{
|
|
CreateDirRecursivelyByFile(file);
|
|
if (access(file.c_str(), 0) != 0) {
|
|
#ifndef _WIN32
|
|
int result = mkdir(file.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); // for linux
|
|
#else
|
|
int result = _mkdir(file.c_str());
|
|
#endif
|
|
if (result < 0) {
|
|
LogError << "mkdir logs file " << file << " fail.";
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create directory recursively by file
|
|
*
|
|
* @param file target file to create
|
|
*/
|
|
void CreateDirRecursivelyByFile(const std::string &file)
|
|
{
|
|
size_t pos = file.rfind('/'); // for linux
|
|
std::string filePath = file.substr(0, pos);
|
|
if (access(filePath.c_str(), 0) != 0) {
|
|
CreateDirRecursivelyByFile(filePath);
|
|
#ifndef _WIN32
|
|
int result = mkdir(filePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); // for linux
|
|
#else
|
|
int result = _mkdir(filePath.c_str());
|
|
#endif
|
|
if (result < 0) {
|
|
LogError << "mkdir logs file " << filePath << " fail.";
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Read a file, store it into the RawData structure
|
|
*
|
|
* @param filePath file to read to
|
|
* @param fileData RawData structure to store in
|
|
* @return APP_ERR_OK if create success, error code otherwise
|
|
*/
|
|
APP_ERROR ReadFile(const std::string &filePath, RawData &fileData)
|
|
{
|
|
std::string resolvedPath;
|
|
APP_ERROR ret = GetRealPath(filePath, resolvedPath);
|
|
if (ret != APP_ERR_OK) {
|
|
return ret;
|
|
}
|
|
// Open file with reading mode
|
|
FILE *fp = fopen(resolvedPath.c_str(), "rb");
|
|
if (fp == nullptr) {
|
|
LogError << "Failed to open file";
|
|
return APP_ERR_COMM_OPEN_FAIL;
|
|
}
|
|
// Get the length of input file
|
|
fseek(fp, 0, SEEK_END);
|
|
long fileSize = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
// If file not empty, read it into FileInfo and return it
|
|
if (fileSize > 0) {
|
|
fileData.lenOfByte = fileSize;
|
|
fileData.data = std::make_shared<uint8_t>();
|
|
fileData.data.reset(new uint8_t[fileSize], std::default_delete<uint8_t[]>());
|
|
size_t readRet = fread(fileData.data.get(), 1, fileSize, fp);
|
|
if (readRet <= 0) {
|
|
fclose(fp);
|
|
return APP_ERR_COMM_READ_FAIL;
|
|
}
|
|
fclose(fp);
|
|
return APP_ERR_OK;
|
|
}
|
|
fclose(fp);
|
|
return APP_ERR_COMM_FAILURE;
|
|
}
|
|
|
|
/**
|
|
* Read a binary file, store the data into a uint8_t array
|
|
*
|
|
* @param fileName the file for reading
|
|
* @param buffShared a shared pointer to a uint8_t array for storing file
|
|
* @param buffLength the length of the array
|
|
* @return APP_ERR_OK if create success, error code otherwise
|
|
*/
|
|
APP_ERROR ReadBinaryFile(const std::string &fileName, std::shared_ptr<uint8_t> &buffShared, int &buffLength)
|
|
{
|
|
// read binary file
|
|
std::ifstream inFile(fileName, std::ios::in | std::ios::binary);
|
|
if (!inFile) {
|
|
LogError << "FaceFeatureLib: read file " << fileName << " fail.";
|
|
return APP_ERR_COMM_READ_FAIL;
|
|
}
|
|
|
|
// get length of file:
|
|
inFile.seekg(0, inFile.end);
|
|
buffLength = inFile.tellg();
|
|
inFile.seekg(0, inFile.beg);
|
|
|
|
auto tempShared = std::make_shared<uint8_t>();
|
|
tempShared.reset(new uint8_t[buffLength], std::default_delete<uint8_t[]>());
|
|
inFile.read((char *)tempShared.get(), buffLength);
|
|
inFile.close();
|
|
buffShared = tempShared;
|
|
|
|
LogDebug << "read file: fileName=" << fileName << ", size=" << buffLength << ".";
|
|
|
|
return APP_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* Read a file with specified offset
|
|
* Only used in Jpegd
|
|
*
|
|
* @param fileName the file for reading
|
|
* @param fileData RawData structure to store in
|
|
* @param offset offset for file
|
|
* @return APP_ERR_OK if create success, error code otherwise
|
|
*/
|
|
APP_ERROR ReadFileWithOffset(const std::string &fileName, RawData &fileData, const uint32_t offset)
|
|
{
|
|
std::string resolvedPath;
|
|
APP_ERROR ret = GetRealPath(fileName, resolvedPath);
|
|
if (ret != APP_ERR_OK) {
|
|
return ret;
|
|
}
|
|
|
|
// Open file with reading mode
|
|
FILE *fp = fopen(resolvedPath.c_str(), "rb");
|
|
if (fp == nullptr) {
|
|
LogError << "Failed to open file";
|
|
return APP_ERR_COMM_OPEN_FAIL;
|
|
}
|
|
// Get the length of input file
|
|
fseek(fp, 0, SEEK_END);
|
|
long fileSize = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
// If file not empty, read it into FileInfo and return it
|
|
if (fileSize > 0) {
|
|
fileData.lenOfByte = fileSize;
|
|
fileData.data = std::make_shared<uint8_t>();
|
|
fileData.data.reset(new uint8_t[fileSize + offset], std::default_delete<uint8_t[]>());
|
|
size_t readRet = fread(fileData.data.get(), 1, fileSize, fp);
|
|
if (readRet <= 0) {
|
|
fclose(fp);
|
|
return APP_ERR_COMM_READ_FAIL;
|
|
}
|
|
fclose(fp);
|
|
return APP_ERR_OK;
|
|
}
|
|
fclose(fp);
|
|
return APP_ERR_COMM_FAILURE;
|
|
}
|
|
|
|
APP_ERROR GetRealPath(const std::string &srcPath, std::string &resolvedPath)
|
|
{
|
|
// Get the absolute path of input file
|
|
#ifndef _WIN32
|
|
char path[PATH_MAX + 1] = {0};
|
|
if ((strlen(srcPath.c_str()) > PATH_MAX) || (realpath(srcPath.c_str(), path) == nullptr)) {
|
|
#else
|
|
#pragma comment(lib, "Shlwapi.lib")
|
|
char path[MAX_PATH + 1] = {0};
|
|
if ((strlen(srcPath.c_str()) > MAX_PATH) || (_fullpath(path, srcPath.c_str(), MAX_PATH) == nullptr)) {
|
|
#endif
|
|
LogError << "Failed to get canonicalize path----" << srcPath;
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
}
|
|
resolvedPath = path;
|
|
return APP_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* Get the extension name of input file
|
|
*
|
|
* @param filePath the file for reading extension name
|
|
* @return extension name of the file
|
|
*/
|
|
std::string GetExtension(const std::string &filePath)
|
|
{
|
|
std::set<char> delims { '.' };
|
|
std::vector<std::string> path = SplitPath(filePath, delims);
|
|
return path[path.size() - 1];
|
|
}
|
|
|
|
/**
|
|
* Get file canonical name
|
|
*
|
|
* @param filePath absolute path of the target file
|
|
* @return filename of the file
|
|
*/
|
|
std::string GetName(const std::string &filePath)
|
|
{
|
|
std::set<char> delims { '/' };
|
|
std::vector<std::string> path = SplitPath(filePath, delims);
|
|
return (path.size() < 1) ? "" : path[path.size() - 1];
|
|
}
|
|
|
|
/**
|
|
* Get the Parent of input file
|
|
*
|
|
* @param filePath file for looking for parent
|
|
* @return parent of the file
|
|
*/
|
|
std::string GetParent(const std::string &filePath)
|
|
{
|
|
std::set<char> delims { '/' };
|
|
std::vector<std::string> path = SplitPath(filePath, delims);
|
|
return (path.size() < TWO) ? "" : path[path.size() - TWO];
|
|
}
|
|
|
|
/**
|
|
* Change the current directory
|
|
*
|
|
* @param dir target directory to change to
|
|
* @return APP_ERR_OK if create success, error code otherwise
|
|
*/
|
|
APP_ERROR ChangeDir(const std::string &dir)
|
|
{
|
|
std::string resolvedPath;
|
|
APP_ERROR ret = GetRealPath(dir, resolvedPath);
|
|
if (ret != APP_ERR_OK) {
|
|
return ret;
|
|
}
|
|
#ifndef _WIN32
|
|
char path[PATH_MAX + 1] = {0};
|
|
resolvedPath.copy(path, resolvedPath.length());
|
|
char *dName = dirname(path);
|
|
if (dName == nullptr) {
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
}
|
|
#else
|
|
char path[MAX_PATH + 1] = {0};
|
|
resolvedPath.copy(path, resolvedPath.length());
|
|
if (!PathRemoveFileSpecA(path)) {
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
}
|
|
char *dName = path;
|
|
#endif
|
|
if (chdir(dName) != 0) {
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
}
|
|
return APP_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* Append stream to file
|
|
*
|
|
* @param fileName to append to
|
|
* @param stream content of string
|
|
* @param streamLength length of string
|
|
*/
|
|
void SaveFileAppend(const std::string &fileName, const std::string &stream, const int streamLength)
|
|
{
|
|
LogDebug << "saving binary file by app: fileName=" << fileName << ", streamLength=" << streamLength;
|
|
std::ofstream outfile(fileName, std::ios::app | std::ofstream::binary);
|
|
outfile.write(stream.c_str(), streamLength);
|
|
outfile.close();
|
|
}
|
|
|
|
/**
|
|
* Overwrite a file with stream
|
|
*
|
|
* @param fileName to overwrite to
|
|
* @param stream content of string
|
|
* @param streamLength length of string
|
|
*/
|
|
void SaveFileOverwrite(const std::string &fileName, const std::string &stream, const int streamLength)
|
|
{
|
|
LogDebug << "Saving binary file by over write: fileName=" << fileName << ", streamLength=" << streamLength;
|
|
std::ofstream outfile(fileName, std::ios::out | std::ofstream::binary);
|
|
outfile.write(stream.c_str(), streamLength);
|
|
outfile.close();
|
|
}
|
|
|
|
/**
|
|
* Copy file
|
|
*
|
|
* @param srcFile from source
|
|
* @param destFile to destination
|
|
*/
|
|
void CopyFile(const std::string &srcFile, const std::string &destFile)
|
|
{
|
|
std::ifstream in(srcFile, std::ios::binary);
|
|
if (!in) {
|
|
LogError << "Failed to get source file, it may be not exists. srcFile=" << srcFile;
|
|
return;
|
|
}
|
|
std::ofstream out(destFile, std::ios::binary);
|
|
if (!out) {
|
|
LogError << "Failed to save destination file. destFile=" << destFile;
|
|
in.close();
|
|
return;
|
|
}
|
|
char flush[BUFFER_SIZE];
|
|
while (!in.eof()) {
|
|
in.read(flush, BUFFER_SIZE);
|
|
out.write(flush, in.gcount());
|
|
}
|
|
out.close();
|
|
in.close();
|
|
}
|
|
|
|
/**
|
|
* Save file with timestamp under specified folder
|
|
*
|
|
* @param dataBuffer buffer of file
|
|
* @param bufferSize buffer size
|
|
* @param folderName specified folder will be created if it not existed
|
|
* @param fileName file name without suffix, the finally name will append time stamp to it
|
|
* @param fileSuffix suffix name of file
|
|
*/
|
|
APP_ERROR SaveFileWithTimeStamp(std::shared_ptr<void> dataBuffer, uint32_t bufferSize, std::string folderName,
|
|
std::string fileName, std::string fileSuffix)
|
|
{
|
|
#ifndef _WIN32
|
|
SetFileDefaultUmask();
|
|
#endif
|
|
APP_ERROR ret;
|
|
if (folderName.length() != 0) {
|
|
ret = CreateDir(folderName);
|
|
if (ret != APP_ERR_OK) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
// Result file name use the time stamp as a suffix
|
|
std::string timeString;
|
|
GetCurTimeString(timeString);
|
|
|
|
// Create file under folderName directory
|
|
std::stringstream resultPathName;
|
|
if (folderName.length() == 0) {
|
|
resultPathName << "./" << fileName << "_" << timeString << fileSuffix;
|
|
} else {
|
|
resultPathName << folderName << "/" << fileName << "_" << timeString << fileSuffix;
|
|
}
|
|
std::string resolvedPath;
|
|
ret = GetRealPath(resultPathName.str(), resolvedPath);
|
|
if (ret != APP_ERR_OK) {
|
|
return ret;
|
|
}
|
|
|
|
FILE *fp = fopen(resolvedPath.c_str(), "wb");
|
|
if (fp == nullptr) {
|
|
LogError << "Failed to open file";
|
|
return APP_ERR_COMM_OPEN_FAIL;
|
|
}
|
|
uint32_t result = fwrite(dataBuffer.get(), 1, bufferSize, fp);
|
|
if (result != bufferSize) {
|
|
LogError << "Failed to write file";
|
|
fclose(fp);
|
|
return APP_ERR_COMM_WRITE_FAIL;
|
|
}
|
|
LogInfo << "Write result to file successfully";
|
|
uint32_t ff = fflush(fp);
|
|
if (ff != 0) {
|
|
LogError << "Failed to fflush file";
|
|
fclose(fp);
|
|
return APP_ERR_COMM_DESTORY_FAIL;
|
|
}
|
|
uint32_t fc = fclose(fp);
|
|
if (fc != 0) {
|
|
LogError << "Failed to fclose file";
|
|
return APP_ERR_COMM_DESTORY_FAIL;
|
|
}
|
|
return APP_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* Convert the current time to the format "%Y%m%d%H%M%S"
|
|
*
|
|
* @param timeString buffer to save the time string with format "%Y%m%d%H%M%S"
|
|
*/
|
|
void GetCurTimeString(std::string &timeString)
|
|
{
|
|
// Result file name use the time stamp as a suffix
|
|
const int timeZoneDiff = 28800; // 8 hour time difference
|
|
const int timeStringSize = 32;
|
|
char timeStr[timeStringSize] = {0};
|
|
time_t tmValue = time(nullptr) + timeZoneDiff;
|
|
struct tm tmStruct = {0};
|
|
#ifdef _WIN32
|
|
if (0 == gmtime_s(&tmStruct, &tmValue)) {
|
|
#else
|
|
if (nullptr != gmtime_r(&tmValue, &tmStruct)) {
|
|
#endif
|
|
strftime(timeStr, sizeof(timeStr), "%Y%m%d%H%M%S", &tmStruct);
|
|
}
|
|
timeString = timeStr;
|
|
return;
|
|
} |