11
votes

Comment attraper un bloc arbitraire d'un fichier sur Unix / Linux

J'essaie de copier un bloc d'un fichier binaire dans un nouveau fichier. J'ai le décalage des octets et la longueur du morceau que je veux saisir.

J'ai essayé d'utiliser l'utilitaire dd , mais cela semble lire et jeter les données jusqu'au décalage, plutôt que juste Chercher (je suppose parce que DD est destiné à copier / convertir des blocs de données). Cela le rend assez lent (et plus lent le décalage supérieur. C'est la commande que j'ai essayée: xxx

Je suppose que je pouvais écrire un petit Perl / python / quel que soit le script à ouvrir Le fichier, cherche au décalage, puis lisez et écrivez la quantité requise de données dans des morceaux.

existe-t-il un utilitaire qui prend en charge quelque chose comme ça?


2 commentaires

Je viens d'essayer d'exécuter strace sur DD, il a utilisé llsek.


Ah, je suis sur Freebsd, alors peut-être que c'est une implémentation différente. Peut-être que c'est lent car je définissais la taille de la mémoire tampon d'entrée sur 1 octet.


6 Réponses :


0
votes

Vous pouvez utiliser l'option

--input-position=POS


0 commentaires

13
votes

Vous pouvez utiliser queue -c + n code> pour couper les n octets de tête de l'entrée, vous pouvez utiliser tête -cm code> pour produire uniquement les premiers m octets de son INPUT.

tail -c+$offset inputfile | head -c$datalength > outputfile


0 commentaires

1
votes

Merci pour les autres réponses. Malheureusement, je ne suis pas en mesure d'installer des logiciels supplémentaires. L'option DDRESCUE est donc sortie. La solution de tête / queue est intéressante (je ne me suis pas réalisée que vous pourriez fournir + à la queue), mais la numérisation à travers les données le rend assez lent.

J'ai fini par écrire un petit script Python pour faire ce que je voulais. La taille de la mémoire tampon doit probablement être à l'écoute d'être identique à celle du réglage de la mémoire tampon externe, mais en utilisant la valeur ci-dessous suffisamment performante sur mon système. P>

#!/usr/local/bin/python

import sys

BUFFER_SIZE = 100000

# Read args
if len(sys.argv) < 4:
    print >> sys.stderr, "Usage: %s input_file start_pos length" % (sys.argv[0],)
    sys.exit(1)
input_filename = sys.argv[1]
start_pos = int(sys.argv[2])
length = int(sys.argv[3])

# Open file and seek to start pos
input = open(sys.argv[1])
input.seek(start_pos)

# Read and write data in chunks
while length > 0:
    # Read data
    buffer = input.read(min(BUFFER_SIZE, length))
    amount_read = len(buffer)

    # Check for EOF
    if not amount_read:
        print >> sys.stderr, "Reached EOF, exiting..."
        sys.exit(1)

    # Write data
    sys.stdout.write(buffer)
    length -= amount_read


1 commentaires

La taille de la mémoire tampon doit être suffisamment grande pour maintenir le nombre de syscalls (et de commutateurs de contexte) vers le bas et un multiple de la taille de la page pour rendre la mise en cache aussi heureuse que possible. Le noyau Readahead signifie qu'il n'aura probablement pas d'effet réel sur la taille du disque I / OS demandé. 100000 N'est-ce pas un multiple de 4Kib, mais les valeurs de 64Kib à 1MIB sont raisonnables.



1
votes

Selon man dd sur FreeBSD :

skip = n

Passer n blocs du début de l'entrée avant de copier. sur l'entrée qui supporte la recherche, une opération LSEOK (2) est utilisée. Sinon, les données d'entrée sont lues et supprimées. Pour les tuyaux, le Le nombre correct d'octets est lu. Pour tous les autres appareils, le Le nombre correct de blocs est lu sans distinction entre un bloc partiel ou complet en cours de lecture.

Utilisation DTRUSS J'ai vérifié qu'il utilise lsek () sur un fichier d'entrée sur Mac OS X. Si vous pensez simplement que c'est lent, je suis d'accord avec le commentaire que cela serait dû à la taille du bloc de 1 octet.


0 commentaires

10
votes

Oui, il est gênant de le faire avec DD aujourd'hui. Nous envisageons d'ajouter Skip_Bytes et Count_Bytes paramètres sur DD dans Coreutils pour vous aider. Ce qui suit devrait fonctionner cependant:

#!/bin/sh

bs=100000
infile=$1
skip=$2
length=$3

(
  dd bs=1 skip=$skip count=0
  dd bs=$bs count=$(($length / $bs))
  dd bs=$(($length % $bs)) count=1
) < "$infile"


1 commentaires

Ouais, ajoutant Skip / Count_bytes serait vraiment utile et faire de la DD un but général faciles à utiliser Byte-Grabber :)



0
votes

Vous pouvez essayer la commande heexdummp: xxx pré>

ex.) Lisez 100 octets de 'mycorefile' à partir de décalage 100. p>

# /usr/bin/hexdump  -v -C  mycorefile -n 100 -s 100
00000064  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000074  00 00 00 00 01 00 00 00  05 00 00 00 00 10 03 00  |................|
00000084  00 00 00 00 00 00 40 00  00 00 00 00 00 00 00 00  |......@.........|
00000094  00 00 00 00 00 00 00 00  00 00 00 00 00 a0 03 00  |................|
000000a4  00 00 00 00 00 10 00 00  00 00 00 00 01 00 00 00  |................|
000000b4  06 00 00 00 00 10 03 00  00 00 00 00 00 90 63 00  |..............c.|
000000c4  00 00 00 00                                       |....|
000000c8
#


0 commentaires