Показать полную графическую версию : Кучка (heap)
Здравствуйте!
Меня интересует как в программе на Си обрабатывать кучу файлов, заданных по маске параметром командной строки как один входной источник? (файлы не копируются друг в друга! в любой момент времени мы должны точно значть из какого именно файла мы считываем)
Синтаксис запуска, например, таков:
myprogram.exe *.TEXT
При таком запуске программа должна обрабатывать в качестве входного потока все файлы с расширением .TEXT, которые лежат в папке с ней.
Товарищи Керниган и Ритчи предлагают только filecopy... ((
DillerInc
13-04-2010, 22:05
ManHack, дык, перечислите все файлы в папке, чтобы узнать их кол-во, а после выделите память(можно и кучи можно через VirtualAlloc, зависит от конкретного примера) для таблицы, которая будет содержать структуры следующего типа:
opened_file struc
hFile dd ? ; Описатель файла, чтобы потом к нему обращаться
pFileName dd ? ; Указатель на буфер, содержащий путь к файлу
pFileMem dd ? ; Указатель на память со считаным файлом
opened_file ends
Для буфера пути файла лучше использовать кучу, т.к. она лучше подходит для выделения небольших размеров памяти.А файл лучше считывать в память, выделенную через VirtualAlloc.
Ну, и далее по обстоятельствам.
Вот про указатели на память со считанным файлом можно поподробнее?
Каким образом это реализуется на Си? Я понимаю что есть "указатель на файл", но фраза "указатель на память" вносит некое смятение в мои мысли. Проясните пожалуйста.
DillerInc
14-04-2010, 00:19
ManHack, я вам не скажу, как это делается именно на Си, т.к. не пишу на этом языке, но на WinAPI это делается следующим образом:
1. Открываем файл с помощью CreateFile
2. Узнаём размер файла с помощью GetFileSize
3. Выделяем нужное кол-во памяти через VirtualAlloc, основываясь на полученном размере файла
4. И считываем открытый файл в эту память при помощи ReadFile
Вот у вас и получился указатель на память, содержащую считаный файл.
А что такое указатель на файл? Его описатель(который handle)? Если да, то понятие указатель здесь несовсем подходит.
Спасибо! Но я слышал, что в Си можно совершенно стандартным образом обрабатывать кучу файлов по маске.
Например, в Паскале есть команда, возвращающая первый файл из директории, которые подпадает под заданную маску (к примеру, какую-нибудь такую: ABS*.PAS)
Также там есть команда, которая позволяет получить следующий файл, удовлетворяющий такой маске из той же директории. А далее можно организовать цикл...
В Си тоже есть что-то аналогичное и тоже совершенно стандартное, но упоминаний в руководствах об этом я не нашёл.
Хотелось бы разузнать как такие вещи реализуются именно на Си...
Например, в Паскале есть команда, возвращающая первый файл из директории, которые подпадает под заданную маску (к примеру, какую-нибудь такую: ABS*.PAS) »
я так понял что нужны функции FindFirstFile, FindNextFile, FindClose (windows.h)?
либо findfirst, findnext (dir.h)
в любом случае стандартными их назвать можно только для windows и dos. В юниксе не прокатят.
виндовые функции упоминаются в руководстве msdn, а так же помогает поиск в инете по их названиям.
Ещё пишут что аналогично работает opendir, который есть в юниксе, но меня описание не впечатлило.
А я бы посоветовал, если обработка файлов ведётся независимо, сделать в программе так, чтобы она принимала названия файлов со входного потока, и запускать её так:
dir /s /b /a-d *.pas | my_program
один косяк: у винды глюкавый dir. Если он встретит папку 1.pas, то перечислит всё её содержимое. В юниксе таких проблем нет.
pva, для Юникса по идеи должен помочь исходник ls.
так и есть, а моя любимая - find и/или grep
На славу потрудившись, я написал следующий код:
void ResetText() {
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFile( Path , &FindFileData );
puts("FindFileData.cFileName");
if( FindFileData.cFileName == NULL ) {
puts("Формат вызова:\n O <входной файл>");
exit(1);
}
else if( (f = fopen(FindFileData.cFileName, "r")) == NULL ){
ResetError = TRUE;
Message = "Входной файл не найден";
}
else {
ResetError = FALSE; Message = "Ok";
Pos = 0; Line = 1;
NextCh();
}
do {
if( hFind && !( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
if( FindFileData.cFileName == NULL ) {
puts("Формат вызова:\n O <входной файл>");
exit(1);
}
else if( (f = fopen(FindFileData.cFileName, "r")) == NULL ){
ResetError = TRUE;
Message = "Входной файл не найден";
}
else {
ResetError = FALSE; Message = "Ok";
Pos = 0; Line = 1;
NextCh();
}
}
} while( FindNextFile( hFind, &FindFileData ) );
FindClose(hFind);
}
Невероятно, но он компилируется в MS Visual Studio 2008 как код на Си.
Теперь проблема: скармливаю я ему, значит, консольный ввод:
MyProgram.exe InputFile.txt
А он мне врёт:
Входной файл не найден
Что я сделал не так?
PS> Как из WIN32_FIND_DATA конвертировать, скажем, в формат массива из символов?
1) что такое Path? откуда он взялся?
2) посоветую изначально занулить WIN32_FIND_DATA
3) насколько я помню, cFileName - это и есть массив из MAX_PATH_LENGTH символов (а не указатель), поэтому if( FindFileData.cFileName == NULL ) { »
никогда не сработает
Написал совсем по-человечески:
O.C
/* Љ®¬ЇЁ«пв®а п§лЄ* Ћ (o.c) */
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <time.h>
#include <string.h>
#include "text.h"
#include "scan.h"
#include "scan.h"
#include "location.h"
#include "pars.h"
#include "error.h"
void Init(void) {
ResetText();
if( ResetError )
Error(Message);
InitScan();
}
void Done(void) {
CloseText();
}
int main(int argc, char *argv[]) {
struct _finddata_t c_file;
intptr_t hFile;
puts("\n бла-бла-бла");
if( argc <= 1 )
Mask = NULL;
else
Mask = argv[1];
hFile = _findfirst( Mask, &c_file );
if( (hFile = _findfirst( Mask, &c_file )) == -1L ) {
printf( "%s", "Файлов, удовлетворяющих маске " );
printf( "%s", Mask );
printf( "%s", "не найдено.\n" );
} else {
do {
strcpy(Path, &c_file.name);
Init();
Compile();
Done();
} while( _findnext( hFile, &c_file ) == 0 );
_findclose( hFile );
}
return 0;
}
Этот самый ResetText():
char ResetError = TRUE;
char* Message = "”*©« *Ґ ®вЄалв";
int Ch = chEOT;
static FILE *f;
void NextCh() {
if( (Ch = fgetc(f)) == EOF )
Ch = chEOT;
else if( Ch == '\n' ) {
//readln(f);// ??
// puts("");
Line++; Pos = 0; Ch = chEOL;
}
else if( Ch == '\r' )
NextCh();
else if( Ch != '\t' ) {
// putchar(Ch);
Pos++;
}
// else
// do
// putchar(' ');
// while( ++Pos % TABSIZE );
}
void ResetText() {
if( Path == NULL ) {
puts("Запуск*:\n MyProgram.exe <вход. файл>");
exit(1);
}
else if( (f = fopen(Path, "r")) == NULL ){
ResetError = TRUE;
Message = "Что-то пошло не так с открытием файла*";
}
else {
ResetError = FALSE; Message = "Ok";
Pos = 0; Line = 1;
NextCh();
}
}
Теперь первый файл по маске программа читает нормально, а вот когда под маску подпадают несколько файлов, то когда дело доходит до второго возникает ошибка:
http://pix.sparky-s.ie/465a6.jpg
Ошибка возникает на втором файле, т.к. я пробовал выводить значение переменной Path когда они присваиваются - выдало 1-е имя файла из папки, удовлетворяющее маске и 2-е, потом ошибка.
В чём причина неполадки? Почему программа не хочет обрабатывать последующие файлы? (их имена она определяет правильно)
При компиляции проекта в MS Visual Studio 2008 ошибок не возникало... Помогите.
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.