2016-07-22 46 views
6

Czy można wywoływać narzędzia CLI, takie jak pdftotext, antywojenny, catdoc (skrypty ekstraktora tekstowego) przekazujące ciąg zamiast pliku?Przekazywanie ciągów przechowywanych w pamięci do pdftotekstu, antyspordu, catdoc, itp.

Obecnie czytam pliki PDF wywołujące pdftotext z child_process.spawn. Odradzam nowy proces i zapisuję wynik w nowej zmiennej. Wszystko dziala.

Chciałbym przekazać binary od A fs.readFile zamiast samego pliku:

fs.readFile('./my.pdf', (error, binary) => { 
    // Call pdftotext with child_process.spawn passing the binary. 
    let event = child_process.spawn('pdftotext', [ 
     // Args here! 
    ]); 
}); 

W jaki sposób można to zrobić?

Odpowiedz

2

Jest to zdecydowanie możliwe, jeśli polecenie może obsłużyć wejście przewodowe.

spawn zwraca obiekt ChildProcess, można przekazać do niego ciąg (lub binarny), zapisując go na jego stdin. Łańcuch powinien być najpierw converted na ReadableStream, następnie można napisać ciąg do stdin z CLI przez pipe.

createReadStream tworzy ReadableStream z pliku.

Poniższy przykład pobiera plik pdf i przesyła zawartość do pdftotext, a następnie wyświetla pierwsze kilka bajtów wyniku.

const source = 'http://static.googleusercontent.com/media/research.google.com/en//archive/gfs-sosp2003.pdf' 
const http = require('http') 
const spawn = require('child_process').spawn 

download(source).then(pdftotext) 
.then(result => console.log(result.slice(0, 77))) 

function download(url) { 
    return new Promise(resolve => http.get(url, resolve)) 
} 

function pdftotext(binaryStream) { 
    //read input from stdin and write to stdout 
    const command = spawn('pdftotext', ['-', '-']) 
    binaryStream.pipe(command.stdin) 

    return new Promise(resolve => { 
    const result = [] 
    command.stdout.on('data', chunk => result.push(chunk.toString())) 
    command.stdout.on('end',() => resolve(result.join(''))) 
    }) 
} 

Dla CLIS nie mają możliwość odczytu z stdin, można użyć named pipes.

Edytuj: Dodaj kolejny przykład z nazwanymi potokami.

Po utworzeniu nazwanych potoków można używać ich jako plików. Poniższy przykład tworzy tymczasowe nazwane potoki do wysyłania danych wejściowych i uzyskiwania danych wyjściowych oraz wyświetla pierwsze kilka bajtów wyniku.

const fs = require('fs') 
const spawn = require('child_process').spawn 

pipeCommand({ 
    name: 'wvText', 
    input: fs.createReadStream('document.doc'), 
}).then(result => console.log(result.slice(0, 77))) 

function createPipe(name) { 
    return new Promise(resolve => 
    spawn('mkfifo', [name]).on('exit',() => resolve())) 
} 

function pipeCommand({name, input}) { 
    const inpipe = 'input.pipe' 
    const outpipe = 'output.pipe' 
    return Promise.all([inpipe, outpipe].map(createPipe)).then(() => { 
    const result = [] 
    fs.createReadStream(outpipe) 
    .on('data', chunk => result.push(chunk.toString())) 
    .on('error', console.log) 

    const command = spawn(name, [inpipe, outpipe]).on('error', console.log) 
    input.pipe(fs.createWriteStream(inpipe).on('error', console.log)) 
    return new Promise(resolve => 
     command.on('exit',() => { 
     [inpipe, outpipe].forEach(name => fs.unlink(name)) 
     resolve(result.join('')) 
     })) 
    }) 
} 
+0

Hei @DarkKnight, dużo tranków !! Jeśli nie pytam o wiele, czy mógłbyś podać przykładowy efekt z nazwanymi potokami? Okazuje się, że używam innych skryptów, które nie obsługują innej metody. –

+0

z pytaniem *, przykład * –

+0

Wszystkie wymienione narzędzia mogą akceptować 'stdin' przez podanie' -'. Dodałem jeszcze inny przykład. – DarkKnight