Maison  >  Article  >  développement back-end  >  Quel est le moyen le plus efficace de lire un fichier d'octets dans une tranche int64 ?

Quel est le moyen le plus efficace de lire un fichier d'octets dans une tranche int64 ?

PHPz
PHPzavant
2024-02-09 11:36:09920parcourir

将字节文件读入 int64 切片的最有效方法是什么?

L'éditeur PHP Zimo est là pour répondre à une question courante : "Quel est le moyen le plus efficace de lire des fichiers d'octets dans des tranches int64 ?" Lorsque nous avons besoin de lire des fichiers d'octets dans des tranches int64, nous pouvons utiliser l'approche suivante : Tout d'abord, utilisez la fonction file_get_contents pour lire le fichier d'octets, puis utilisez la fonction unpack pour décompresser le fichier d'octets en tranches int64. Cette méthode est simple et efficace, et peut rapidement convertir des fichiers d'octets en tranches int64 pour répondre à nos besoins. J'espère que cette méthode pourra aider tout le monde !

Contenu de la question

J'ai plusieurs fichiers int64 compressés. J'en ai besoin en mémoire sous forme de tranches int64. Le problème est que les fichiers combinés dépassent la moitié de la taille de la mémoire de la machine, l'espace est donc limité. Les options standard en go ressemblent à :

a := make([]int64, f.Size()/8)
binary.Read(f, binary.LittleEndian, a)

Malheureusement, binary 包将立即分配一个大小为 f.size()*8[]byte, et manque de mémoire.

Cela fonctionne si je lis chaque octet un par un et que je le copie dans la tranche, mais c'est trop lent.

La situation idéale serait d'utiliser []byte 直接转换为 []int64 et de dire simplement au compilateur "ok, ce sont des entiers maintenant", mais évidemment cela ne fonctionne pas. Existe-t-il un moyen de réaliser quelque chose de similaire ? Peut-être utiliser un package dangereux ou le mettre en c lorsque cela est absolument nécessaire ?

Solution de contournement

J'ai plusieurs fichiers int64 compressés. J'en ai besoin en mémoire sous forme de tranches int64. Le problème est que les fichiers combinés dépassent la moitié de la taille de la mémoire de la machine, l'espace est donc limité.

Les options standard de Go ressemblent à :

a := make([]int64, f.Size()/8)
binary.Read(f, binary.LittleEndian, a)

Malheureusement, le package binaire allouera immédiatement un []octet de taille f.size()*8 et manquera de mémoire.

Toutes les fonctions utilisent un minimum de mémoire.

// same endian architecture and data
// most efficient (no data conversion).
func readfileint64se(filename string) ([]int64, error) {
    b, err := os.readfile(filename)
    if err != nil {
        return nil, err
    }

    const i64size = int(unsafe.sizeof(int64(0)))
    i64ptr := (*int64)(unsafe.pointer(unsafe.slicedata(b)))
    i64len := len(b) / i64size
    i64 := unsafe.slice(i64ptr, i64len)

    return i64, nil
}

Par exemple, pour une architecture amd64 (littleendian) et une efficacité maximale avec les données littleendian (aucune conversion de données requise), utilisez readfileint64se.

Erreur d'ordre des octets - Rob Pike
https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

// littleendian in-place data conversion for any architecture
func readfileint64le(filename string) ([]int64, error) {
    b, err := os.readfile(filename)
    if err != nil {
        return nil, err
    }

    const i64size = int(unsafe.sizeof(int64(0)))
    i64ptr := (*int64)(unsafe.pointer(unsafe.slicedata(b)))
    i64len := len(b) / i64size
    i64 := unsafe.slice(i64ptr, i64len)

    for i, j := i64size, 0; i <= len(b); i, j = i+i64size, j+1 {
        i64[j] = int64(binary.littleendian.uint64(b[i-i64size : i]))
    }

    return i64, nil
}
// BigEndian in-place data conversion for any architecture
func readFileInt64BE(filename string) ([]int64, error) {
    b, err := os.ReadFile(filename)
    if err != nil {
        return nil, err
    }

    const i64Size = int(unsafe.Sizeof(int64(0)))
    i64Ptr := (*int64)(unsafe.Pointer(unsafe.SliceData(b)))
    i64Len := len(b) / i64Size
    i64 := unsafe.Slice(i64Ptr, i64Len)

    for i, j := i64Size, 0; i <= len(b); i, j = i+i64Size, j+1 {
        i64[j] = int64(binary.BigEndian.Uint64(b[i-i64Size : i]))
    }

    return i64, nil
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer