Por que não podemos inserir arquivos sem as gravações adicionais? (Não quero acrescentar, nem sobrescrever)


8

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 Catrás b, meu código precisa ser reescrito dddpara obter

aaabCddd

Por que não posso simplesmente inserir Cnesta 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 Cque simplesmente não pode ser inserido sem as gravações adicionais. Alguém poderia explicar por que isso é assim?


2
Pense no que acontece com os bits no disco quando você deseja 'inserir' algo no byte 128 de um arquivo de 2 gigabytes.

Você quer dizer sem sistema operacional e sem sistema de arquivos no meio? Então não vai funcionar. Com os outros dois no lugar, não tenho idéia do porquê não pode funcionar.
Utilizador

12
Pegue 500 dominós e coloque-os de ponta a ponta em uma linha. Agora tente inserir um nessa linha sem mover os outros.
GrandmasterB

2
@ MichaelT No mundo dos meus sonhos, você só deve inserir outro bloco na sequência de blocos que compõe o arquivo e distribuir o conteúdo do primeiro bloco atual nos dois primeiros. Concedido, isto exigiria que os implementadores do sistema de arquivos para lidar com blocos de estranho porte - mas nas situações em que você não precisa esta operação, seria melhorar a eficiência tanto que não é mesmo engraçado.
precisa saber é o seguinte

1
@User: questões de fragmentação do sistema de arquivos e como o Ext4 funciona firmemente no domínio do SuperUser. Lembre- se de especificar completamente o seu problema ou eles voltarão a perguntar sobre bytes. Você está perguntando sobre blocos e sistemas de arquivos e gerenciadores de volume lógico e similares.

Respostas:


8

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.


2
Prédio que pode fazer um projeto paralelo interessante por um tempo ...
FrustratedWithFormsDesigner

1
O armazenamento em nível de bloco complica a questão um passo adiante. Seguindo o exemplo original do OP, as duas versões da string devem caber em um único bloco. Os bytes precisam ser gravados seqüencialmente e é isso que precisa mudar a cauda da string para baixo, independentemente da quantidade inserida.

Seria eficiente se você tivesse que inserir exatamente a quantidade de dados que pode ser armazenada em um bloco, exatamente na borda entre os dois blocos existentes.
Idan Arye

Kilian Forth parece estar certo. Perguntei a um professor sobre isso e ele me falou sobre o mesmo: O design "áspero e simples" permite portabilidade e, portanto, é mais amplamente usado. Poucos sistemas de arquivos permitem a inserção e ainda menos sistemas operacionais a expõem, a serem aplicados a uma interface portátil. @ GlenH7 Duas pessoas que editaram minha pergunta fizeram com que parecesse que eu perguntasse sobre bytes e reverti meus esclarecimentos. A verdadeira questão é sobre a interface que usamos.
Utilizador

Sim, os blocos são vinculados por meio de ponteiros e, portanto, o conteúdo do arquivo não precisa ser armazenado de forma contígua, mas quando eles são armazenados de forma contígua, o hardware pode ler bloco após bloco sem precisar diminuir a velocidade. Se tivesse que seguir ponteiro por ponteiro, a cabeça de leitura estaria constantemente se movendo. É por isso que a desfragmentação ajuda a acelerar o seu computador. Ele coloca os ponteiros de bloco para arquivos em blocos contíguos. Então o comando não é o bloco de leitura 1, o bloco de leitura 3, o bloco de leitura 9, o bloco de leitura n ... torna-se o bloco de leitura 1 a n. O hardware pode fazer isso com muito mais eficiência.
Dunk

12

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.


3
Eu também mencionaria o desafio de "procurar o bloco que está em 1 gigabyte de um arquivo de 2 gigabytes" pode demorar um pouco com a implementação da lista vinculada de bytes.

A questão do que acontece durante as inserções é causa de grande consternação entre as pessoas que projetam a deduplicação para sistemas de armazenamento.
Blrfl

Obrigado por entender que eu não pretendia falar sobre bytes, mas sobre o quadro geral.
Utilizador

8

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:

Address  Value
0x00     `a`
0x01     `a`
0x02     `a`
0x03     `b`
0x04     `d`
0x05     `d`
0x06     `d`

E você deseja inserir Cna 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.

Address  Value
0x00     `a`
0x01     `a`
0x02     `a`
0x03     `b`
0x04     `C`
0x05     `d`
0x06     `d`
0x07     `d`

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 bpor C, 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 abcom Centã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.

dominó

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.


Suponha que ab C e d não sejam caracteres, mas gigabytes de caracteres. Você poderia resolver isso em sua resposta? Gosto da imagem, mas também acho que as pessoas se aproximariam de inserir 1000 dominós em 2000 dominós de maneira diferente que 1 dominó em 6 dominós.
Utilizador

@ Usuário - GB de caracteres em vez de bytes altera fundamentalmente a natureza da sua pergunta e agora os blocos de armazenamento devem ser considerados. Em um nível simples, a resposta é a mesma. Você não pode inserir algo em uma série contígua de "whatevers" sem criar espaço.

0

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.


este não parece oferecer nada substancial sobre anteriores 6 respostas
mosquito

Você pode escrever todo o software que desejar, mas isso não mudará a maneira como o hardware funciona. O hardware funciona lendo / escrevendo em blocos / páginas. Em um HDD, se esses dados não forem contíguos, o cabeçote de leitura deverá se mover, o que diminui drasticamente o tempo de acesso ao arquivo. Qualquer operação de inserção "pelo fato de ser uma inserção" deve ser armazenada em outro local e não de forma contígua. Certamente, a inserção possivelmente será mais rápida (para arquivos muito grandes), mas a leitura será muito mais lenta.
Dunk

0

A maneira mais eficiente de inserir um bloco de bytes no meio de um arquivo seria:

  1. Mapear o arquivo para a memória
  2. Anexe os bytes no final da imagem de memória do arquivo
  3. Gire esses arquivos no lugar (com um algoritmo padrão disponível na Biblioteca Padrão C ++, por exemplo)
  4. Deixe o sistema operacional gravar blocos sujos no disco

-1

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.


1
O que confina com um SSD com acesso aleatório? Os arquivos também são divididos em partes pelo sistema de arquivos. Como isso se relaciona em escrever tudo de novo?
Utilizador

@ Usuário com certeza pode acessá- lo aleatoriamente (embora você não esteja acessando o nível de bits, ainda o está bloqueando) ... mas como você diz o byte a seguir?

1
O SSD ainda lê e grava uma página de cada vez. Portanto, para escrever seu byte de 1 bytes que você deseja inserir, você deverá escrever uma página inteira de dados, além de atualizar todas as tabelas / indicadores do sistema de arquivos correspondentes. Eu não ficaria surpreso se os sistemas de arquivos iniciais tivessem uma operação de inserção, mas eles perceberam que isso acrescentava muito mais sobrecarga do que economizava.
Dunk

-1

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.