利用直接读dmp文件,字符串匹配和配对括号来提取DDL语句,不依赖odv_api函数。导出csv仍然依靠odv_api函数。
c
#include "odv_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <getopt.h>
#ifdef _WIN32
#include <direct.h>
#define MKDIR(dir) _mkdir(dir)
#else
#include <sys/stat.h>
#define MKDIR(dir) mkdir(dir, 0755)
#endif
/*---------------------------------------------------------------------------
Global variables
---------------------------------------------------------------------------*/
static const char *g_output_dir = ".";
static char **g_table_list = NULL;
static int g_table_count = 0;
static char g_delimiter = ',';
static int g_write_header = 1;
static int g_write_types = 0;
static int g_export_all = 1;
/*---------------------------------------------------------------------------
Table list structure for collecting table info
---------------------------------------------------------------------------*/
#define MAX_TABLES 200
typedef struct {
int count;
char names[MAX_TABLES][256];
char schemas[MAX_TABLES][256];
long long row_counts[MAX_TABLES];
} TableList;
static TableList g_tables;
static int g_export_success_count = 0;
static int g_export_fail_count = 0;
/*---------------------------------------------------------------------------
print_usage
---------------------------------------------------------------------------*/
static void print_usage(const char *program_name)
{
printf("Usage: %s <dump_file> [options]\n\n", program_name);
printf("Options:\n");
printf(" -o <dir> Output directory (default: current directory)\n");
printf(" -t </td> Export specific table (can be used multiple times)\n");
printf(" -a Export all tables (default)\n");
printf(" -d <delimiter> CSV delimiter character (default: ',')\n");
printf(" -H Write header row (default: enabled)\n");
printf(" -T Write column types row after header\n");
printf(" -h Show this help message\n\n");
printf("Examples:\n");
printf(" %s export.dmp -o ./output -a\n", program_name);
printf(" %s export.dmp -t TABLE1 -t TABLE2 -o ./csv_files\n", program_name);
printf(" %s export.dmp -t EMPLOYEES -d '|' -H\n", program_name);
}
/*---------------------------------------------------------------------------
create_directory
---------------------------------------------------------------------------*/
static int create_directory(const char *path)
{
if (MKDIR(path) == 0) {
return 1;
}
return 1; /* Assume directory exists */
}
/*---------------------------------------------------------------------------
sanitize_filename - replace invalid characters with underscore
---------------------------------------------------------------------------*/
static void sanitize_filename(const char *input, char *output, int output_size)
{
int i, j = 0;
for (i = 0; input[i] && j < output_size - 1; i++) {
char c = input[i];
if (c == '/' || c == '\\' || c == ':' || c == '*' ||
c == '?' || c == '"' || c == '<' || c == '>' || c == '|') {
output[j++] = '_';
} else {
output[j++] = c;
}
}
output[j] = '\0';
}
/*---------------------------------------------------------------------------
build_output_path
---------------------------------------------------------------------------*/
static char* build_output_path(const char *output_dir, const char *table_name)
{
char *full_path = NULL;
char safe_table_name[256];
int len;
sanitize_filename(table_name, safe_table_name, sizeof(safe_table_name));
len = strlen(output_dir) + strlen(safe_table_name) + 10;
full_path = (char*)malloc(len);
if (full_path) {
sprintf(full_path, "%s/%s.csv", output_dir, safe_table_name);
}
return full_path;
}
/*---------------------------------------------------------------------------
table_callback - called for each table when listing tables
---------------------------------------------------------------------------*/
static void __stdcall table_callback(
const char *schema,
const char *table,
int col_count,
const char **col_names,
const char **col_types,
const int *col_not_nulls,
const char **col_defaults,
int constraint_count,
const char *constraints_json,
long row_count,
long data_offset,
void *user_data)
{
TableList *tl = (TableList *)user_data;
if (tl->count < MAX_TABLES) {
strncpy(tl->schemas[tl->count], schema ? schema : "", 255);
strncpy(tl->names[tl->count], table ? table : "", 255);
tl->schemas[tl->count][255] = '\0';
tl->names[tl->count][255] = '\0';
tl->row_counts[tl->count] = row_count;
tl->count++;
printf(" Found table: %s (schema: %s, columns: %d, rows: %lld)\n",
table, schema, col_count, (long long)row_count);
}
}
/*---------------------------------------------------------------------------
instr - find substring in binary data (handles embedded \0)
haystack: pointer to binary data
haystack_len: length of haystack in bytes
needle: search string (null-terminated)
Returns: pointer to first occurrence, or NULL if not found
---------------------------------------------------------------------------*/
static char* instr(const char *haystack, size_t haystack_len, const char *needle)
{
size_t needle_len = strlen(needle);
if (needle_len == 0 || haystack_len < needle_len) {
return NULL;
}
for (size_t i = 0; i <= haystack_len - needle_len; i++) {
size_t j;
for (j = 0; j < needle_len; j++) {
if (haystack[i + j] != needle[j]) {
break;
}
}
if (j == needle_len) {
return (char*)&haystack[i];
}
}
return NULL;
}
/*---------------------------------------------------------------------------
export_schema_for_table - export CREATE TABLE DDL for a specific table
Directly read DMP file and extract CREATE TABLE statement by string matching
---------------------------------------------------------------------------*/
static int export_schema_for_table(const char *dump_file, const char *table_name,
const char *output_dir)
{
FILE *dmp_fp = NULL;
FILE *schema_file = NULL;
char schema_path[512];
char *file_content = NULL;
long file_size;
int rc = -1;
/* Build schema file path */
snprintf(schema_path, sizeof(schema_path), "%s/schema.sql", output_dir);
/* Open dump file */
dmp_fp = fopen(dump_file, "rb");
if (!dmp_fp) {
return -1;
}
/* Get file size */
fseek(dmp_fp, 0, SEEK_END);
file_size = ftell(dmp_fp);
fseek(dmp_fp, 0, SEEK_SET);
/* Read entire file */
file_content = (char*)malloc(file_size + 1);
if (!file_content) {
fclose(dmp_fp);
return -1;
}
fread(file_content, 1, file_size, dmp_fp);
file_content[file_size] = '\0';
fclose(dmp_fp);
/* Open schema file for append */
schema_file = fopen(schema_path, "a");
if (!schema_file) {
free(file_content);
return -1;
}
/* Build search pattern: CREATE TABLE "TABLE_NAME" */
char search_pattern[512];
snprintf(search_pattern, sizeof(search_pattern), "CREATE TABLE \"%s\"", table_name);
/* Search for pattern in binary data */
char *found = instr(file_content, file_size, search_pattern);
if (found) {
char *start = found;
char *paren_start = NULL;
char *end = NULL;
int paren_count = 0;
/* Find the first '(' after CREATE TABLE */
for (char *p = start; p < file_content + file_size; p++) {
if (*p == '(') {
paren_start = p;
break;
}
}
if (paren_start) {
/* Find matching closing parenthesis */
end = paren_start;
while (end < file_content + file_size) {
if (*end == '(') {
paren_count++;
} else if (*end == ')') {
paren_count--;
if (paren_count == 0) {
end++;
break;
}
}
end++;
}
}
if (end && end > start) {
int ddl_len = end - start;
char *ddl = (char*)malloc(ddl_len + 1);
if (ddl) {
strncpy(ddl, start, ddl_len);
ddl[ddl_len] = '\0';
/* Write to schema file */
fprintf(schema_file, "\n-- Table: %s\n", table_name);
fputs(ddl, schema_file);
fprintf(schema_file, ";\n");
free(ddl);
rc = 0;
}
}
}
if (rc != 0) {
fprintf(schema_file, "\n-- Table: %s (CREATE TABLE statement not found)\n", table_name);
}
fclose(schema_file);
free(file_content);
return rc;
}
/*---------------------------------------------------------------------------
export_single_table - export one table to CSV
---------------------------------------------------------------------------*/
static int export_single_table(ODV_SESSION *session, const char *dump_file,
const char *table_name, const char *output_path,
const char *output_dir)
{
int rc;
/* Export schema (CREATE TABLE) first */
export_schema_for_table(dump_file, table_name, output_dir);
/* Set CSV options */
odv_set_csv_options(session, g_write_header, g_write_types);
odv_set_csv_delimiter(session, g_delimiter);
/* Export to CSV */
rc = odv_export_csv(session, table_name, output_path);
return rc;
}
/*---------------------------------------------------------------------------
export_all_tables - export all tables from dump file
---------------------------------------------------------------------------*/
static int export_all_tables(const char *dump_file, const char *output_dir)
{
ODV_SESSION *session = NULL;
TableList tables;
int rc;
int i;
int exported = 0;
int dump_type;
printf("Phase 1: Listing tables in %s\n", dump_file);
printf("----------------------------------------\n");
/* Initialize table list */
memset(&tables, 0, sizeof(tables));
/* Create session and list tables */
rc = odv_create_session(&session);
if (rc != ODV_OK || !session) {
printf("ERROR: Failed to create session\n");
return -1;
}
rc = odv_set_dump_file(session, dump_file);
if (rc != ODV_OK) {
printf("ERROR: Failed to set dump file: %s\n", odv_get_last_error(session));
odv_destroy_session(session);
return -1;
}
odv_check_dump_kind(session, &dump_type);
odv_set_table_callback(session, table_callback, &tables);
odv_list_tables(session);
printf("\nFound %d tables\n\n", tables.count);
if (tables.count == 0) {
printf("No tables found in dump file.\n");
odv_destroy_session(session);
return 0;
}
/* Create output directory */
create_directory(output_dir);
printf("Phase 2: Exporting tables to CSV\n");
printf("----------------------------------------\n");
/* Initialize schema.sql file */
char schema_path[512];
snprintf(schema_path, sizeof(schema_path), "%s/schema.sql", output_dir);
FILE *schema_file = fopen(schema_path, "w");
if (schema_file) {
fprintf(schema_file, "-- Oracle DMP Schema Export\n");
fprintf(schema_file, "-- Generated by OraDB Dump Viewer\n");
fprintf(schema_file, "-- Export time: %s\n\n", __DATE__ " " __TIME__);
fclose(schema_file);
}
/* Export each table - create new session for each export */
for (i = 0; i < tables.count; i++) {
char *output_path = build_output_path(output_dir, tables.names[i]);
ODV_SESSION *export_session = NULL;
if (!output_path) {
printf(" [%d/%d] Table: %s -> SKIP (memory allocation failed)\n",
i + 1, tables.count, tables.names[i]);
g_export_fail_count++;
continue;
}
printf(" [%d/%d] Exporting table: %s -> %s\n",
i + 1, tables.count, tables.names[i], output_path);
/* Create new session for each export to avoid state issues */
rc = odv_create_session(&export_session);
if (rc != ODV_OK || !export_session) {
printf(" ERROR: Failed to create session\n");
free(output_path);
g_export_fail_count++;
continue;
}
rc = odv_set_dump_file(export_session, dump_file);
if (rc != ODV_OK) {
printf(" ERROR: Failed to set dump file: %s\n",
odv_get_last_error(export_session));
odv_destroy_session(export_session);
free(output_path);
g_export_fail_count++;
continue;
}
/* Export to CSV */
rc = export_single_table(export_session, dump_file, tables.names[i], output_path, output_dir);
if (rc == ODV_OK) {
long file_size;
FILE *f = fopen(output_path, "rb");
if (f) {
fseek(f, 0, SEEK_END);
file_size = ftell(f);
fclose(f);
} else {
file_size = 0;
}
printf(" SUCCESS: %ld bytes, %lld rows\n",
file_size, (long long)tables.row_counts[i]);
exported++;
g_export_success_count++;
} else {
printf(" FAILED: %s\n", odv_get_last_error(export_session));
g_export_fail_count++;
}
odv_destroy_session(export_session);
free(output_path);
}
odv_destroy_session(session);
printf("\nExport completed: %d/%d tables exported successfully.\n",
exported, tables.count);
return 0;
}
/*---------------------------------------------------------------------------
export_selected_tables - export only specified tables
---------------------------------------------------------------------------*/
static int export_selected_tables(const char *dump_file, const char *output_dir,
char **table_list, int table_count)
{
ODV_SESSION *session = NULL;
int rc;
int i;
int exported = 0;
int dump_type;
printf("Exporting %d specified tables...\n\n", table_count);
/* Create output directory */
create_directory(output_dir);
/* Initialize schema.sql file */
char schema_path[512];
snprintf(schema_path, sizeof(schema_path), "%s/schema.sql", output_dir);
FILE *schema_file = fopen(schema_path, "w");
if (schema_file) {
fprintf(schema_file, "-- Oracle DMP Schema Export\n");
fprintf(schema_file, "-- Generated by OraDB Dump Viewer\n");
fprintf(schema_file, "-- Export time: %s\n\n", __DATE__ " " __TIME__);
fclose(schema_file);
}
/* Export each table - create new session for each export to avoid state issues */
for (i = 0; i < table_count; i++) {
char *output_path = build_output_path(output_dir, table_list[i]);
if (!output_path) {
printf(" [%d/%d] Table: %s -> SKIP (memory allocation failed)\n",
i + 1, table_count, table_list[i]);
g_export_fail_count++;
continue;
}
printf(" [%d/%d] Exporting table: %s -> %s\n",
i + 1, table_count, table_list[i], output_path);
/* Create new session for each export */
rc = odv_create_session(&session);
if (rc != ODV_OK || !session) {
printf(" ERROR: Failed to create session\n");
free(output_path);
g_export_fail_count++;
continue;
}
rc = odv_set_dump_file(session, dump_file);
if (rc != ODV_OK) {
printf(" ERROR: Failed to set dump file: %s\n",
odv_get_last_error(session));
odv_destroy_session(session);
free(output_path);
g_export_fail_count++;
continue;
}
/* Export to CSV */
rc = export_single_table(session, dump_file, table_list[i], output_path, output_dir);
if (rc == ODV_OK) {
long file_size;
FILE *f = fopen(output_path, "rb");
if (f) {
fseek(f, 0, SEEK_END);
file_size = ftell(f);
fclose(f);
} else {
file_size = 0;
}
printf(" SUCCESS: %ld bytes\n", file_size);
exported++;
g_export_success_count++;
} else {
printf(" FAILED: %s\n", odv_get_last_error(session));
g_export_fail_count++;
}
odv_destroy_session(session);
session = NULL;
free(output_path);
}
printf("\nExport completed: %d/%d tables exported successfully.\n",
exported, table_count);
return 0;
}
/*---------------------------------------------------------------------------
main
---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
const char *dump_file = NULL;
int opt;
/* Parse command line arguments */
while ((opt = getopt(argc, argv, "o:t:d:HTah")) != -1) {
switch (opt) {
case 'o':
g_output_dir = optarg;
break;
case 't':
if (!g_table_list) {
g_table_list = (char**)malloc(sizeof(char*) * 100);
}
g_table_list[g_table_count] = strdup(optarg);
g_table_count++;
g_export_all = 0;
break;
case 'd':
g_delimiter = optarg[0];
break;
case 'H':
g_write_header = 1;
break;
case 'T':
g_write_types = 1;
break;
case 'a':
g_export_all = 1;
break;
case 'h':
print_usage(argv[0]);
return EXIT_SUCCESS;
default:
print_usage(argv[0]);
return EXIT_FAILURE;
}
}
/* Check if dump file is specified */
if (optind >= argc) {
fprintf(stderr, "Error: Dump file not specified\n\n");
print_usage(argv[0]);
return EXIT_FAILURE;
}
dump_file = argv[optind];
/* Check if file exists */
FILE *test = fopen(dump_file, "rb");
if (!test) {
fprintf(stderr, "Error: Cannot open dump file: %s\n", dump_file);
return EXIT_FAILURE;
}
fclose(test);
printf("========================================\n");
printf("OraDB DUMP Viewer - CSV Export Tool\n");
printf("Version: %s\n", odv_get_version());
printf("========================================\n");
printf("Dump file: %s\n", dump_file);
printf("Output directory: %s\n", g_output_dir);
printf("CSV delimiter: '%c'\n", g_delimiter);
printf("Write header: %s\n", g_write_header ? "Yes" : "No");
printf("Write types: %s\n", g_write_types ? "Yes" : "No");
printf("========================================\n\n");
/* Export tables */
if (g_export_all) {
export_all_tables(dump_file, g_output_dir);
} else if (g_table_count > 0) {
export_selected_tables(dump_file, g_output_dir, g_table_list, g_table_count);
} else {
fprintf(stderr, "Error: No tables specified for export\n");
return EXIT_FAILURE;
}
/* Cleanup */
if (g_table_list) {
for (int i = 0; i < g_table_count; i++) {
free(g_table_list[i]);
}
free(g_table_list);
}
printf("\nFinal results: %d succeeded, %d failed\n",
g_export_success_count, g_export_fail_count);
return (g_export_fail_count > 0) ? EXIT_FAILURE : EXIT_SUCCESS;
}
输出
./dmp2csv2 /par/exptest.dmp -o out3
========================================
OraDB DUMP Viewer - CSV Export Tool
Version: 3.1.0
========================================
Dump file: /par/exptest.dmp
Output directory: out3
CSV delimiter: ','
Write header: Yes
Write types: No
========================================
Phase 1: Listing tables in /par/exptest.dmp
----------------------------------------
Found table: IGNORE (schema: EXPTEST, columns: 1, rows: 0)
Found table: IGNORE2 (schema: EXPTEST, columns: 2, rows: 0)
Found table: TABLE1 (schema: EXPTEST, columns: 7, rows: 0)
Found table: TABLE2 (schema: EXPTEST, columns: 3, rows: 4)
Found 4 tables
Phase 2: Exporting tables to CSV
----------------------------------------
[1/4] Exporting table: IGNORE -> out3/IGNORE.csv
SUCCESS: 0 bytes, 0 rows
[2/4] Exporting table: IGNORE2 -> out3/IGNORE2.csv
SUCCESS: 0 bytes, 0 rows
[3/4] Exporting table: TABLE1 -> out3/TABLE1.csv
SUCCESS: 0 bytes, 0 rows
[4/4] Exporting table: TABLE2 -> out3/TABLE2.csv
SUCCESS: 64 bytes, 4 rows
Export completed: 4/4 tables exported successfully.
Final results: 4 succeeded, 0 failed
schema.sql
-- Oracle DMP Schema Export
-- Generated by OraDB Dump Viewer
-- Export time: Apr 7 2026 11:49:08
-- Table: IGNORE
CREATE TABLE "IGNORE" ("COLUMN1" VARCHAR2(20));
-- Table: IGNORE2
CREATE TABLE "IGNORE2" ("COLUMN1" VARCHAR2(20), "COLUMN2" VARCHAR2(21));
-- Table: TABLE1
CREATE TABLE "TABLE1" ("KEYCOL" NUMBER(*,0) NOT NULL ENABLE, "NUMCOL1" NUMBER(22, 0), "FLOATCOL1" FLOAT(126), "STRCOL1" VARCHAR2(200), "DATECOL1" DATE, "BLOBCOL1" BLOB, "TIMESTAMP1" TIMESTAMP (6));
-- Table: TABLE2
CREATE TABLE "TABLE2" ("STRKEY" VARCHAR2(20) NOT NULL ENABLE, "FLOAT1" FLOAT(126), "DEC1" NUMBER(22, 5));
TABLE2.csv
STRKEY,FLOAT1,DEC1
K1,1,14
K2,0.2,2.99992
K3,-0.3,-0.00232
K4,,