2013-03-21 4 views
6

Come scrivere su stdout dall'applicazione console Delphi?Come scrivere dati binari nello stdout in Delphi?

Ecco cosa ho provato. Ho truccato questa semplice applicazione di test in base alle informazioni che ho trovato, per leggere un file dal disco e l'output per consolare stdout:

program ConsoleOut; 
{$APPTYPE CONSOLE} 
uses 
    Classes, Windows, SysUtils; 

var 
    S: TMemoryStream; 
    OutputStream: THandleStream; 
    ss: string; 
    Buffer: PByte; 
    i: Integer; 
begin 
    S := TMemoryStream.Create; 
    S.LoadFromFile('1.jpg'); 
    S.Seek(0, soFromBeginning); 

    //Am I right that from now on writing to OutputStream will write to stdout? 
    OutputStream := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE)); 

    GetMem(Buffer, S.Size); 
    S.ReadBuffer(Buffer^, S.Size); 
    i := OutputStream.Write(Buffer^, S.Size); //i = 0 here for some reason 
    FreeMem(Buffer, S.Size); 

    Writeln(i, ' byte written to output'); 
    Readln(ss); //Don't exit app to read previous line 
    S.Free; 
end. 

Ma per qualche motivo viene a mancare. Potresti per favore indirizzarmi nel modo corretto di scrivere su stdout?

+0

curioso PERCHE 'vuoi scrivere il rumore binario sulla console? Hai menzionato qualcosa sul text to speech. Perché non i pipe nominati? –

+1

Quali vantaggi hanno le pipe denominate rispetto allo stdout? – Kromster

+0

Progettato per il trasferimento di dati gravi invece delle interfacce utente, su Windows. L'output standard Unix viene utilizzato di routine come pipe di dati anonimi. Dos e Windows non lo usano abitualmente. Come hai imparato. –

risposta

7

Il tuo approccio è valido. Tuttavia, se lo stdout è collegato a una console, il codice non funziona. Una chiamata al GetLastError seguendo la scrittura flusso rivela il codice di errore ERROR_NOT_ENOUGH_MEMORY:

insufficiente archiviazione è disponibile per elaborare il comando.

Se si reindirizza lo stdout in un file, il codice funzionerà correttamente. E sicuramente non vuoi veramente rilasciare dati binari sulla console. Questo sta per mettere dei contenuti illeggibili sulla console e far suonare il computer in modo fastidioso!

Se è necessario eseguire l'output sulla console, è necessario scoprire quanto è grande il buffer della console e scrivere in blocchi di dimensioni appropriate. Devo confessare che non sono sicuro di come lo farai. Potresti usare prove ed errori, ma questo non mi piace. Presumibilmente c'è un modo per interrogare la console per scoprire le informazioni.

Guardando la documentazione per WriteConsole, sembra che 64 KB sia il limite superiore. E infatti se scrivo spazi al tuo stream di handle, allora posso scrivere quasi 64K in una volta. Tuttavia, se scrivo dati binari JPEG grezzi, viene distribuito prima. Quindi penso che sia parte del problema anche - non scaricare un JPEG sulla console.

Un altro commento. Poiché si legge il contenuto del file in un flusso di memoria, non è necessario allocare un buffer intermedio. È possibile scrivere direttamente S.Memory^.

+1

Grazie per il suggerimento, ho pensato che se la console è vuota non funziona, ma il reindirizzamento dello stdout a un file ("appname.exe> ​​out.jpg") ha funzionato bene. – Kromster

+1

In un sidenote: sto lavorando a un'app che ha bisogno di generare e generare da testo a voce nello stdout, quindi sì, sono i dati binari e molti di essi (pochi Mb). Ma la tua risposta copre molti aspetti, quindi per favore non tagliarla, in modo che sia utile per gli altri) – Kromster

+0

@KromStern: il tuo ultimo commento non ha senso. Se stai facendo 'text to speech allo stdout' e poi reindirizzando' stdout' in un file, puoi semplicemente fare "text to speech to file" e ritagliare il middleman di 'stdout'. Non ha senso scrivere alla console per reindirizzare immediatamente quell'output su un file. –