2010-10-05 26 views
6

Comment lire une ligne FIFO/nommée ligne par ligne à partir d'une application Linux C++/Qt?Comment lire une ligne FIFO/nommée ligne par ligne à partir d'une application Linux C++/Qt?

Aujourd'hui, je peux ouvrir et lire à partir d'un fifo à partir d'un programme Qt, mais je ne peux pas obtenir le programme pour lire les données ligne par ligne. Qt lit tout le fichier, ce qui signifie qu'il attend que l'expéditeur ferme sa session. Prenons un exemple avec quelques commandes shell pour montrer ce que je voudrais que l'application fasse.

d'abord créer un fifo

mkfifo MyPipe 

Ensuite, nous pouvons utiliser le chat pour lire la fifo

cat MyPipe 

Et puis nous envoyons des données avec un autre chat

cat > MyPipe 

Et puis commencez à taper quelque chose, et chaque fois que vous frappez entrer, il arrive au lecteur. Et puis quand vous le fermez avec Ctrl + D les deux côtés se terminent.

Maintenant, l'expéditeur est facile à créer avec un QTextStream, vous avez juste besoin de vider quand vous voulez envoyer.

QFile file("MyPipe"); 
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) 
    return; 

QTextStream out(&file); 
for(int i=0; i<3; i++) { 
    out << "Hello...: " << i << "\n"; 
    out.flush(); 
    sleep(2); 
} 

file.close(); 

Mais alors d'écrire un petit lecteur qui a lu ligne par ligne est où je suis coincé en ce moment, tous mes essais avec la lib Qt finit avec ce que je reçois les données, mais pas jusqu'à ce que l'expéditeur utilise file.close() sur le fifo. Pas quand il rougit, comme cela se produit lorsque j'utilise chat pour lire.

Comme cet exemple:

QFile file("MyPipe"); 
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) 
    return 0; 

QTextStream in(&file); 
QString line; 
do { 
    line = in.readLine(); 
    qDebug() << line; 
} while (!in.atEnd()); 


file.close(); 

Qu'est-ce que je manque?

Il se sent juste comme je l'ai besoin d'utiliser une sorte de isReady ou lineAvailable sur cours d'eau ou quelque chose comme ça, mais je ne trouve rien dans les documents qui s'intègre ...

/Merci


Remarque:

Si je vais avec le style bas niveau c et lu un omble chevalier au moment où je fais obtenir le style Im mer rching pour. Mais ce serait bien de pouvoir faire le même style Qt.

FILE *fp; 
fp=fopen("MyPipe", "r"); 
char c; 
while((c=getc(fp)) != EOF) 
{ 
    printf("%c",c); 
} 
fclose(fp); 

Mise à jour:

Quand je démarre un débogueur le programme est accroché au readLine(), et ne pas continuer jusqu'à ce que l'autre partie ferme la fifo.

Et je reçois la même chose en utilisant « >> »

line = in.readLine(); 
    in >> line; 
+1

Se pourrait-il que le tube soit en train d'être lu immédiatement, et que c'est la sortie d'écran qui est tamponnée? Vous avez utilisé 'qDebug() << line;' et je ne vois aucun rinçage. –

+0

Bon point, n'y ai pas pensé. – Johan

Répondre

4

Utilisez le style de niveau inférieur c et lisez un caractère à la fois.

FILE *fp; 
fp=fopen("MyPipe", "r"); 
char c; 
while((c=getc(fp)) != EOF) 
{ 
    printf("%c",c); 
} 
fclose(fp); 
+0

'c' doit être' int' sinon ce pourrait être une boucle infinie si 'char' est non signé (' EOF' est un entier négatif ('-1' généralement)). – jfs

2

Je ne sais pas ce qui ne fonctionne pas, mais vous pouvez essayer de le déboguer en utilisant strace:

strace -o writer.log -e trace=write ./writer 
strace -o reader.log -e trace=read ./reader 

Le premier la ligne enregistrera tout l'appel du système d'écriture effectué par votre programme d'écriture. La deuxième ligne fonctionne de la même manière. De cette façon, vous pouvez suivre l'appel système et être sûr que votre rinçage fonctionne.

Si vous voyez des appels répétés à lire, avec la synchronisation et les données correctes, alors vous avez un problème avec QTextStream. Que se passe-t-il si vous n'utilisez pas QTextStream, mais lisez directement à partir du fichier?

+0

strace est sympa, et j'ai commencé un "watch tail reader.log" dans une autre fenêtre et je peux voir qu'il obtient les données que je lui envoie. – Johan

+0

@Johan: êtes-vous sûr que le problème est du côté du lecteur? – shodanex

+0

95% sûr puisque si je remplace la "version Qt" par la "version C" cela fonctionne. – Johan

1

Vous pouvez essayer d'ouvrir le fichier du côté du lecteur avec le drapeau QIODevice::Unbuffered.

+1

L'idée de Dieu, mais c'est toujours le même :( – Johan

2
if(file.bytesAvailable()) 
QString line = file.readLine(); 

Vous pouvez utiliser quelque chose comme ça.

+0

L'implémentation QFile de bytesAvailable NE FONCTIONNE PAS pour les fichiers spéciaux, y compris les canaux nommés, et bloque en fait l'application! –