Войти

Показать полную графическую версию : Кучка (heap)


ManHack
13-04-2010, 20:51
Здравствуйте!
Меня интересует как в программе на Си обрабатывать кучу файлов, заданных по маске параметром командной строки как один входной источник? (файлы не копируются друг в друга! в любой момент времени мы должны точно значть из какого именно файла мы считываем)
Синтаксис запуска, например, таков:
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.
Ну, и далее по обстоятельствам.

ManHack
13-04-2010, 23:26
Вот про указатели на память со считанным файлом можно поподробнее?
Каким образом это реализуется на Си? Я понимаю что есть "указатель на файл", но фраза "указатель на память" вносит некое смятение в мои мысли. Проясните пожалуйста.

DillerInc
14-04-2010, 00:19
ManHack, я вам не скажу, как это делается именно на Си, т.к. не пишу на этом языке, но на WinAPI это делается следующим образом:
1. Открываем файл с помощью CreateFile
2. Узнаём размер файла с помощью GetFileSize
3. Выделяем нужное кол-во памяти через VirtualAlloc, основываясь на полученном размере файла
4. И считываем открытый файл в эту память при помощи ReadFile
Вот у вас и получился указатель на память, содержащую считаный файл.
А что такое указатель на файл? Его описатель(который handle)? Если да, то понятие указатель здесь несовсем подходит.

ManHack
14-04-2010, 13:40
Спасибо! Но я слышал, что в Си можно совершенно стандартным образом обрабатывать кучу файлов по маске.
Например, в Паскале есть команда, возвращающая первый файл из директории, которые подпадает под заданную маску (к примеру, какую-нибудь такую: ABS*.PAS)
Также там есть команда, которая позволяет получить следующий файл, удовлетворяющий такой маске из той же директории. А далее можно организовать цикл...
В Си тоже есть что-то аналогичное и тоже совершенно стандартное, но упоминаний в руководствах об этом я не нашёл.
Хотелось бы разузнать как такие вещи реализуются именно на Си...

pva
14-04-2010, 15:33
Например, в Паскале есть команда, возвращающая первый файл из директории, которые подпадает под заданную маску (к примеру, какую-нибудь такую: 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, то перечислит всё её содержимое. В юниксе таких проблем нет.

Admiral
14-04-2010, 15:39
pva, для Юникса по идеи должен помочь исходник ls.

pva
14-04-2010, 20:52
так и есть, а моя любимая - find и/или grep

ManHack
06-05-2010, 22:59
На славу потрудившись, я написал следующий код:
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 конвертировать, скажем, в формат массива из символов?

pva
08-05-2010, 12:57
1) что такое Path? откуда он взялся?
2) посоветую изначально занулить WIN32_FIND_DATA
3) насколько я помню, cFileName - это и есть массив из MAX_PATH_LENGTH символов (а не указатель), поэтому if( FindFileData.cFileName == NULL ) { »
никогда не сработает

ManHack
11-05-2010, 20:11
Написал совсем по-человечески:
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