Isso ocorre como um problema independente da linguagem de programação para mim.
Eu tenho um arquivo com o conteúdo
aaabddd
Quando quero inserir C
atrás b
, meu código precisa ser reescrito ddd
para obter
aaabCddd
Por que não posso simplesmente inserir C
nesta posição?
Não posso fazer isso em Java, Python, .... Não posso fazer isso no Linux, Windows, .... Estou certo?
Eu não entendo por C
que simplesmente não pode ser inserido sem as gravações adicionais. Alguém poderia explicar por que isso é assim?
programming-languages
operating-systems
file-systems
files
Do utilizador
fonte
fonte
Respostas:
Dado que a maioria dos sistemas de arquivos armazena o conteúdo dos arquivos em blocos individuais que não são necessariamente contíguos no disco físico, mas vinculados por estruturas de ponteiros, parece que esse modo - "inserir" em vez de "anexar" ou "substituir" - deveria para ser possível e certamente poderia se tornar mais eficiente do que o que temos que fazer agora: ler todo o conteúdo, editar o fluxo de bytes e reescrever todo o conteúdo.
No entanto, para o bem ou para o mal, a semântica do UNIX dos sistemas de arquivos foi projetada segundo o paradigma "áspero e simples" da década de 1970: permite fazer tudo, mas não necessariamente da maneira mais eficiente possível. Hoje em dia é quase impensável introduzir um novo modo de abertura de arquivo na camada Virtual File System e ter alguma esperança de que os principais sistemas de arquivos adotem suporte para ele. Esta é uma irritação minha, mas infelizmente não é provável que seja resolvida tão cedo.
fonte
Teoricamente, você pode implementar um arquivo que permita esse tipo de coisa. Para máxima flexibilidade, no entanto, você precisará armazenar um ponteiro para o próximo byte, juntamente com todos os bytes no arquivo. Supondo um ponteiro de 64 bits, isso significaria que 8 de cada 9 bytes do seu arquivo seriam compostos de ponteiros internos. Portanto, seriam necessários 9000 bytes de espaço para armazenar 1000 bytes de dados reais. A leitura do arquivo também seria lenta, já que você precisaria ler cada byte, ler o ponteiro, seguir o ponteiro para ler o próximo byte etc., em vez de ler grandes blocos contíguos de dados do disco.
Obviamente, esse tipo de abordagem não é prático. Você pode, no entanto, dividir o arquivo em, digamos, blocos de 32 kb. Isso tornaria relativamente fácil adicionar 32 kb de dados em qualquer limite de 32 kb no arquivo. Não seria mais fácil adicionar um único byte como o quinto byte do arquivo. Se você reservar algum espaço livre em cada bloco, poderá permitir pequenas adições de dados que afetariam apenas os dados naquele bloco único. Você teria uma penalidade em termos de tamanho do arquivo, é claro, mas potencialmente uma razoável. Descobrir quanto espaço reservar e como dividir blocos, no entanto, tende a ser muito mais fácil para um aplicativo específico do que para um sistema de uso geral - o que funciona em um contexto pode ser muito ruim em outro, dependendo do acesso ao arquivo e características de modificação.
De fato, muitos sistemas que passam muito tempo interagindo com arquivos implementam algo como o que descrevi acima quando implementam sua abstração de arquivo específica. Os bancos de dados, por exemplo, geralmente implementam algum conceito de "bloco" como a menor unidade de E / S com a qual eles podem trabalhar e geralmente reservam uma quantidade de espaço para crescimento futuro, para que a atualização de uma linha em uma tabela afete apenas o um bloco no qual esses dados são armazenados, em vez de reescrever o arquivo inteiro. Diferentes bancos de dados, é claro, têm implementações diferentes com diferentes trade-offs.
fonte
O "problema" se resume a como os arquivos são gravados na mídia de armazenamento, byte a byte.
Em sua representação mais básica, um arquivo nada mais é do que uma série de bytes gravados no disco (também conhecido como meio de armazenamento). Portanto, sua string original se parece com:
E você deseja inserir
C
na posição 0x04. Isso requer a alteração de bytes de 4 a 6 para um byte, para que você possa inserir o novo valor. Caso contrário, você substituirá o valor atualmente em 0x04, que não é o que você deseja.Portanto, a razão pela qual você deve reescrever a cauda do arquivo após inserir um novo valor é porque não há espaço no arquivo para aceitar o valor inserido. Caso contrário, você escreveria o que estava lá.
Adendo 1 : Se você deseja substituir o valor de
b
porC
, não será necessário reescrever a cauda da string. Substituir um valor por um valor de tamanho semelhante não requer uma reescrita.Adenda 2 : Se você queria substituir a string
ab
comC
então você teria necessidade de re-escrever o resto do arquivo como você criou uma lacuna no arquivo.Adendo 3 : Construções em nível de bloco foram criadas para facilitar o manuseio de arquivos grandes. Em vez de precisar encontrar 1 milhão de espaço contíguo para o seu arquivo, agora você só precisa encontrar 1 milhão de blocos disponíveis para gravar.
Em teoria, você pode construir um sistema de arquivos que faça a ligação byte a byte semelhante ao que os blocos fornecem. Em seguida, você pode inserir um novo byte, atualizando o para | dos ponteiros no ponto apropriado. Eu arriscaria um palpite de que o desempenho seria muito ruim.
Como o Grandmaster B sugeriu , use uma imagem de dominó empilhado para entender visualmente como o arquivo é representado.
Você não pode inserir outro dominó na linha de dominós sem fazer com que tudo caia. Você precisa criar o espaço para o novo dominó movendo os outros para baixo da linha. Mover dominós para baixo da linha é o equivalente a reescrever a cauda do arquivo após o ponto de inserção.
fonte
A inserção em um arquivo não é implementada na maioria dos sistemas de arquivos porque é considerada uma operação "cara" (consumo de tempo e espaço) com repercussões "caras" potencialmente a longo prazo e modos de falha adicionais.
Um sistema de arquivos com semântica de inserção provavelmente usaria shift & insert (potencialmente muito caro quando você insere na frente de um arquivo grande, mas sem / poucos efeitos colaterais a longo prazo) ou algum tipo de alocação de heap generalizada com tamanhos de alocação de tamanho variável ( desempenho muito mal comportado em alguns casos [imagine os rostos dos usuários interativos se eles tentarem salvar um arquivo durante um GC de parar o mundo!]).
Se você quiser experimentar, poderá criar facilmente uma abstração de E / S de arquivo em Java ou Python que implemente a inserção. Se você tiver sucesso e tiver características de desempenho bem comportadas, terá a base para um excelente trabalho de pesquisa. Boa sorte.
fonte
A maneira mais eficiente de inserir um bloco de bytes no meio de um arquivo seria:
fonte
Primeiro, você precisa ler tudo após o ponto de inserção e, em seguida, anotá-lo com o máximo de espaço que deseja inserir. Em seguida, você pode gravar seus dados "inserir" no local correto. Operação de desempenho extremamente ruim, portanto, não é suportada nativamente.
fonte
Ao acessar diretamente um arquivo, você está usando um nível baixo que pode ser usado para criar estruturas mais sofisticadas. Considere criar um banco de dados com seus dados que permita os tipos de acesso necessários, incluindo a inserção.
Seria menos dispendioso se você apenas repetisse o arquivo para não acessar aleatoriamente um deslocamento especificado. Se você precisar de acesso aleatório por deslocamento no arquivo, precisará atualizar o índice para todos os bytes além do ponto de inserção.
Em geral, você pagará na indexação de estruturas de dados, memória para armazenar o índice e acessos extras ao disco para atualizá-lo.
fonte