Some simple file operation functions implemented in C

  Function list:
1) Get file length; The size of file is arbitrary, even more than 4GB.
2) Read file of the middle size into memory; The upper bound of file length is 256MB.
3) Compare two files. The size of file is arbitrary, even more than 4GB. Two dynamically allocated memory buffer block are temporarily used. But the max length of an individual buffer is 64MB.
  File list:
1. Header file:
/**************************************************
* File name: c_file_operation.h
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Sept 11th, 2017
* Description: declare some file operation functions,
    support both Windows and Linux
**************************************************/  


#ifndef HEADER_C_FILE_OPERATION_H
  #define HEADER_C_FILE_OPERATION_H

#define FUNCTION_EXECUTE_SUCCEED      (int)(0)
#define INPUT_INVALID_NULL_PARAMETER  (int)(1)
#define FILE_OPERATION_FAIL           (int)(2)
#define FILE_LENGTH_OUT_OF_SCOPE      (int)(3)
#define MEMORY_ALLOCATION_FAIL        (int)(4)

#define MAX_FILE_BUFFER_LENGTH  (long long)(268435456)  /* 268435456 = 256M */

#define LITTTE_FILE_BUFFER_LENGTH (long long)(1048576)   /* 1048576 = 1M */
#define MEDIUM_FILE_BUFFER_LEGNTH (long long)(8388608)   /* 8388608 = 8M */
#define LARGE_FILE_BUFFER_LENGTH  (long long)(67108864)  /* 67108864 = 64M */

#ifdef  __cplusplus
  extern "C" {
#endif

/**************************************************
* Name: GetFileLength
* Function: get file length
* Parameters:
    file_name[in]  file name, path can be included
    file_len[out]  file length, size in bytes
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
* Notes:
1. Large file is supported. That is, file length can be arbitrary.
2. UTF-16 file_name string is NOT supported.
**************************************************/
int GetFileLength(char *file_name, long long *file_len);

/**************************************************
* Name: ReadFileIntoMemoryBuffer
* Function: read file into memory buffer
* Parameters:
    file_name[in]  file name, path can be included
    pp[out]        a pointer address, that pointer will point 
	               to the memory newly allocated
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
* Notes:
1. The max file length is 256 MB. The upper bound is set 
   deliberately to avoid occupying too much memory.
2. UTF-16 file_name string is NOT supported.
3. This function allocate memory buffer internally. It read 
   a file into the buffer. The buffer length is equal to the 
   file length.
4. FreeFileInMemoryBuffer() MUST be invoked to free memory 
   allocated in this function.
**************************************************/
int ReadFileIntoMemoryBuffer(char *file_name, char **pp);

/**************************************************
* Name: FreeFileInMemoryBuffer
* Function: free memory buffer allocated in ReadFileIntoMemoryBuffer()
* Parameters:
    p[in]  a pointer that points to the allocated memory by 
	       function ReadFileIntoMemoryBuffer()
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
**************************************************/
int FreeFileInMemoryBuffer(char *p);

/**************************************************
* Name: CompareFileInBinaryFormat
* Function: Compare two files
* Parameters:
    file1_name[in]  file name
	file2_name[in]  file name
	result[out]     0  -- two files are identical
	                -1 -- two files are different
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
* Notes:
1. Large file is supported. That is, file length can be arbitrary.
2. Memory buffer of various length is automatically chosen internally 
   according to the file length in order to limit memory usage and 
   improve effiency.
3. A special case: If the length of two files are both 0 byte, the two files are 
   considered identical.
**************************************************/
int CompareFileInBinaryFormat(char *file1_name, char *file2_name, int *result);

#ifdef  __cplusplus
  }
#endif

#endif  /* end of HEADER_C_FILE_OPERATION_H */

2. Source file:

/**************************************************
* File name: c_file_operation.c
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Sept 11th, 2017
* Description: implement some file operation functions,
    support both Windows and Linux
**************************************************/

#include "c_file_operation.h"
#include <sys/types.h>  
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int GetFileLength(char *file_name, long long *file_length)
{
#if defined(_WIN32) || defined(_WIN64)
	struct __stat64 buf;
#else
	struct stat buf;
#endif

	if ( (!(file_name)) || (!(file_length)) )
	{
		return INPUT_INVALID_NULL_PARAMETER;
	}

#if defined(_WIN32) || defined(_WIN64)
	if ( _stat64(file_name, &buf) )
#else
	if ( stat64(file_name, &buf) )
#endif
	{
		return FILE_OPERATION_FAIL;
	}

	*file_length = buf.st_size;
	return FUNCTION_EXECUTE_SUCCEED;
}

int ReadFileIntoMemoryBuffer(char *file_name, char **pp)
{
	int error_code;
	long long file_length;
	int file_len;
	char *pointer;
	FILE *fp;

	if ( (!(file_name)) || (!(pp)) )
	{
		return INPUT_INVALID_NULL_PARAMETER;
	}

	if ( error_code = GetFileLength(file_name, &file_length) )
	{
		return error_code;
	}

	if ( file_length > MAX_FILE_BUFFER_LENGTH )
	{
		return FILE_LENGTH_OUT_OF_SCOPE;
	}

	file_len = (int)(file_length);

	if ( !( fp = fopen(file_name, "rb") ) )
		return FILE_OPERATION_FAIL;

	if ( !(pointer = (char *)malloc(file_len)) )
	{
		fclose(fp);
		return MEMORY_ALLOCATION_FAIL;
	}
	fread(pointer, file_len, 1, fp);
	fclose(fp);
	*pp = pointer;
	return 0;
}

int FreeFileInMemoryBuffer(char *p)
{
	if ( !(p) )
	{
		return INPUT_INVALID_NULL_PARAMETER;
	}

	free(p);
	return 0;
}

int CompareFileInBinaryFormat(char *file1_name, char *file2_name, int *result)
{
	int error_code;
	long long file1_len, file2_len, remain_byte_count;
	char *file1_buf, *file2_buf;
	int buf_len, read_byte_count;
	FILE *fp1, *fp2;

	if ( (!(file1_name)) || (!(file2_name)) || (!(result)) )
	{
		return INPUT_INVALID_NULL_PARAMETER;
	}

	if ( !(strcmp(file1_name, file2_name)) )
	{
		*result = 0;
		return FUNCTION_EXECUTE_SUCCEED;
	}

	if ( error_code = GetFileLength(file1_name, &file1_len) )
	{
		return error_code;
	}

	if ( error_code = GetFileLength(file2_name, &file2_len) )
	{
		return error_code;
	}

	if ( file1_len != file2_len )
	{
		*result = -1;
		return FUNCTION_EXECUTE_SUCCEED;
	}

	if ( !(file1_len))
	{
		*result = 0;
		return FUNCTION_EXECUTE_SUCCEED;
	}

	if ( file1_len <= LITTTE_FILE_BUFFER_LENGTH )
	{
		buf_len = (int)(LITTTE_FILE_BUFFER_LENGTH);
	}
	else
	{
		if ( file1_len <= MEDIUM_FILE_BUFFER_LEGNTH )
		{
			buf_len = (int)(MEDIUM_FILE_BUFFER_LEGNTH);
		}
		else
		{
			buf_len = (int)(LARGE_FILE_BUFFER_LENGTH);
		}
	}

	if ( !(file1_buf = (char *)malloc(buf_len)) )
	{
		return MEMORY_ALLOCATION_FAIL;
	}
	if ( !(file2_buf = (char *)malloc(buf_len)) )
	{
		free(file1_buf);
		return MEMORY_ALLOCATION_FAIL;
	}

	if ( !(fp1 = fopen(file1_name, "rb")) )
	{
		free(file2_buf);
		free(file1_buf);
		return FILE_OPERATION_FAIL;
	}
	if ( !(fp2 = fopen(file2_name, "rb")) )
	{
		fclose(fp1);
		free(file2_buf);
		free(file1_buf);
		return FILE_OPERATION_FAIL;
	}

	remain_byte_count = file1_len;
	while (remain_byte_count > 0)
	{
		if ( remain_byte_count < (long long)(buf_len) )
		{
			read_byte_count = (int)(remain_byte_count);
		}
		else
		{
			read_byte_count = buf_len;
		}
		fread(file1_buf, read_byte_count, 1, fp1);
		fread(file2_buf, read_byte_count, 1, fp2);
		if ( memcmp(file1_buf, file2_buf, read_byte_count) )
		{
			*result = -1;
			fclose(fp2);
			fclose(fp1);
			free(file2_buf);
			free(file1_buf);
			return FUNCTION_EXECUTE_SUCCEED;
		}
		remain_byte_count = remain_byte_count - (long long)(read_byte_count);
	}

	*result = 0;
	fclose(fp2);
	fclose(fp1);
	free(file2_buf);
	free(file1_buf);
	return FUNCTION_EXECUTE_SUCCEED;
}

3. Demo file:
/**************************************************
* File name: test.c
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Sept 11th, 2017
* Description: demonstrate how to use file operation 
    functions declared in file "c_file_operation.h"
* Note: this demo is designed for Windows platform,
    but it can be easily modified to be run on Linux
**************************************************/

#if defined(_WIN32) || defined(_WIN64)
  #define _CRTDBG_MAP_ALLOC
  #include <stdlib.h> 
  #include <crtdbg.h>
#else
  #include <stdlib.h>
#endif

#include "c_file_operation.h"
#include <stdio.h>

int main(void)
{
	int error_code;
	char large_file[] = {"C:\\vitualbox_disk\\OVF-WinXp\\Windows_XP_sp2-disk1.vmdk"};
	long long large_file_len;
	char small_file[] = {"C:\\Windows\\WindowsUpdate.log"};
	long long small_file_len;
	char *p;

	char file1[] = {"C:\\vitualbox_disk\\OVF-WinXp\\Windows_XP_sp2-disk1.vmdk"};
	char file2[] = {"C:\\test\\compare_file\\Windows_XP_sp2-disk1.vmdk.bak"};
	long long file1_len, file2_len;
	int result;

	printf("\n*************************************************\n");
	if ( error_code = GetFileLength(large_file, &large_file_len) )
	{
		printf("Get file \'%s\' length failed!\n ", large_file);
		printf("Error code: %d\n", error_code);
#if defined(_WIN32) || defined(_WIN64)  
        system("pause");  
#endif
		return -1;
	}
	printf("File name: %s\n", large_file);
	printf("File length: %lld bytes.\n", large_file_len);

	if ( error_code = ReadFileIntoMemoryBuffer(large_file, &p) )
	{
		printf("Read file \'%s\' into memory failed!\n", large_file);
		printf("Error code: %d\n", error_code);
	}
	else
	{
		printf("Read file \'%s\' into memory succeeded!\n", large_file);
		FreeFileInMemoryBuffer(p);
		printf("Memory has been freed!\n");
	}

	printf("\n*************************************************\n");
	if ( error_code = GetFileLength(small_file, &small_file_len) )
	{
		printf("Get file \'%s\' length failed!\n ", small_file);
		printf("Error code: %d\n", error_code);
	}
	printf("File name: %s\n", small_file);
	printf("File length: %lld bytes.\n", small_file_len);

	if ( error_code = ReadFileIntoMemoryBuffer(small_file, &p) )
	{
		printf("Read file \'%s\' into memory failed!\n", small_file);
		printf("Error code: %d\n", error_code);
	}
	else
	{
		printf("Read file \'%s\' into memory succeeded!\n", small_file);
		FreeFileInMemoryBuffer(p);
		printf("Memory has been freed!\n");
	}

	printf("\n*************************************************\n");
	printf("Files comparison:\n");
	if ( error_code = GetFileLength(file1, &file1_len) )
	{
		printf("Get file \'%s\' length failed!\n ", file1);
		printf("Error code: %d\n", error_code);
	}
	printf("File 1 name: %s\n", file1);
	printf("File 1 length: %lld bytes.\n", file1_len);

	if ( error_code = GetFileLength(file2, &file2_len) )
	{
		printf("Get file \'%s\' length failed!\n ", file2);
		printf("Error code: %d\n", error_code);
	}
	printf("File 2 name: %s\n", file2);
	printf("File 2 length: %lld bytes.\n", file2_len);

	if ( error_code = CompareFileInBinaryFormat(file1, file2, &result) )
	{
		printf("Compare failed!\n ");
		printf("Error code: %d\n", error_code);
#if defined(_WIN32) || defined(_WIN64)  
        system("pause");  
#endif
		return -1;
	}
	printf("Compare result:\n");
	if ( !(result) )
	{
		printf("The binary content of File 1 is the same as the content of File 2.\n");
	}
	else
	{
		printf("File 1 is different from file 2.\n");
	}

#if defined(_WIN32) || defined(_WIN64)
	system("pause");
	_CrtDumpMemoryLeaks();  /* detect memory leak, only can be used on Windows platform */
#endif
	return 0;
}

  Some Virtual Machine Disk files are used in this Demo.  The length of a VMD file is larger than 2GB.


  Source codes are compiled and tested on the following platforms:

1) 64-bit Windows 7, Visual Studio 2010;


2) CentOS 6.8, GCC 4.4.7 (slightly modified).

猜你喜欢

转载自blog.csdn.net/henter/article/details/77937393
今日推荐