Как безопасно записать в файл?

Вы на правильном пути. Необходимо будет переопределить свойство SnapLines в designr и сделать что-то вроде этого:

Public Overrides ReadOnly Property SnapLines() As System.Collections.IList
    Get
        Dim snapLinesList As ArrayList = TryCast(MyBase.SnapLines, ArrayList)

        Dim offset As Integer
        Dim ctrl As MyControl = TryCast(Me.Control, MyControl)
        If ctrl IsNot Nothing AndAlso ctrl.TextBox1 IsNot Nothing Then
            offset = ctrl.TextBox1.Bottom - 5
        End If

        snapLinesList.Add(New SnapLine(SnapLineType.Baseline, offset, SnapLinePriority.Medium))

        Return snapLinesList

    End Get
End Property

В этом примере usercontrol содержит текстовое поле. Код добавляет новый snapline, который представляет базовую линию для текстового поля. Важная вещь состоит в том, чтобы вычислить смещение правильно.

15
задан Michal Sznajder 28 November 2009 в 09:48
поделиться

7 ответов

Если вы видите документацию Python, в ней четко упоминается, что os.rename () является атомарной операцией. Так что в вашем случае запись данных во временный файл с последующим переименованием его в исходный файл была бы вполне безопасной.

Другой способ может работать следующим образом:

  • пусть исходный файл будет abc.xml
  • создать abc.xml.tmp и записать в него новые данные
  • переименовать abc.xml в abc.xml.bak
  • переименуйте abc.xml.tmp в abc.xml
  • после того, как новый abc.xml будет правильно размещен, удалите abc.xml.bak

Как видите, у вас есть abc.xml.bak, который вы можете использовать его для восстановления, если есть какие-либо проблемы, связанные с файлом tmp и его копированием обратно.

14
ответ дан 1 December 2019 в 00:50
поделиться

Если вы хотите быть POSIX-корректным и сохранить, вам необходимо:

  1. Записать во временный файл
  2. Очистить и fsync файл (или fdatasync )
  3. Переименовать исходный файл

Обратите внимание, что вызов fsync оказывает непредсказуемое влияние на производительность - Linux на ext3 может в результате останавливать дисковый ввод-вывод на целые числа секунд, в зависимости от других невыполненных операций ввода-вывода. О.

Обратите внимание, что переименование является не атомарной операцией в POSIX - по крайней мере, не в отношении данных файла, как вы ожидаете. Однако большинство операционных систем и файловых систем будут работать именно так. Но, похоже, вы пропустили очень обширное обсуждение Linux о Ext4 и гарантиях файловой системы относительно атомарности. Я не знаю точно, где связать, но вот начало: ext4 и потеря данных .

Однако обратите внимание, что во многих системах переименование будет настолько безопасным на практике, насколько вы ожидаете. Однако невозможно добиться и производительности, и надежности при всех возможных конфигурациях Linux!

При записи во временный файл и последующем переименовании временного файла можно было бы ожидать, что операции будут зависимыми и будут должны выполняться по порядку.

Проблема, однако, в том, что большинство, если не все файловые системы разделяют метаданные и данные. Переименование - это только метаданные. Вам это может показаться ужасным, но файловые системы ценят метаданные выше данных (например, ведение журнала в HFS + или Ext3,4)! Причина в том, что метаданные легче, и если метаданные повреждены, повреждена вся файловая система - файловая система, конечно, должна сохранять себя, а затем сохранять данные пользователя в этом порядке.

Ext4 действительно нарушил ожидание переименования , когда он впервые появился, однако для его решения были добавлены эвристики. Проблема заключается в не неудачном переименовании, а в успешном переименовании. Ext4 может успешно зарегистрировать переименование, но не сможет записать данные файла, если вскоре после этого произойдет сбой. В результате получается файл нулевой длины, не содержащий ни исходных, ни новых данных.

Короче говоря, POSIX не дает такой гарантии. Прочтите связанную статью о Ext4 для получения дополнительной информации!

Короче говоря, POSIX не дает такой гарантии. Прочтите связанную статью о Ext4 для получения дополнительной информации!

Короче говоря, POSIX не дает такой гарантии. Прочтите связанную статью о Ext4 для получения дополнительной информации!

11
ответ дан 1 December 2019 в 00:50
поделиться

В Win API я нашел довольно приятную функцию ReplaceFile , которая выполняет то, что следует из названия, даже с дополнительным резервным копированием. Всегда есть способ с помощью комбинации DeleteFile , MoveFile

В общем, то, что вы хотите сделать, действительно хорошо. И я не могу придумать лучшей схемы записи.

5
ответ дан 1 December 2019 в 00:50
поделиться

Стандартное решение:

  1. Напишите новый файл с аналогичным именем. X.ext # например.

  2. Когда этот файл был закрыт (и, возможно, даже прочитан и просчитана контрольная сумма), вы двое переименовываете.

    • X.ext (оригинал) в X.ext ~

    • X .ext # (новый) в X.ext

  3. (Только для сумасшедших параноиков) вызывает функцию синхронизации ОС для принудительной записи грязного буфера.

Никогда ничего не потеряно или невозможно повредить. Единственный глюк может случиться при переименовании. Но вы ничего не потеряли и ничего не испортили. Оригинал можно восстановить вплоть до окончательного переименования.

4
ответ дан 1 December 2019 в 00:50
поделиться

По предложению RedGlyph я добавил реализацию ReplaceFile, которая использует ctypes для доступа к Windows API. Сначала я добавил это в jaraco.windows.api.filesystem.

ReplaceFile = windll.kernel32.ReplaceFileW
ReplaceFile.restype = BOOL
ReplaceFile.argtypes = [
    LPWSTR,
    LPWSTR,
    LPWSTR,
    DWORD,
    LPVOID,
    LPVOID,
    ]

REPLACEFILE_WRITE_THROUGH = 0x1
REPLACEFILE_IGNORE_MERGE_ERRORS = 0x2
REPLACEFILE_IGNORE_ACL_ERRORS = 0x4

Затем я протестировал поведение с помощью этого сценария.

from jaraco.windows.api.filesystem import ReplaceFile
import os

open('orig-file', 'w').write('some content')
open('replacing-file', 'w').write('new content')
ReplaceFile('orig-file', 'replacing-file', 'orig-backup', 0, 0, 0)
assert open('orig-file').read() == 'new content'
assert open('orig-backup').read() == 'some content'
assert not os.path.exists('replacing-file')

Хотя это работает только в Windows, похоже, у него есть много хороших функций, которых не хватало бы другим подпрограммам замены . Подробности см. В документации API .

2
ответ дан 1 December 2019 в 00:50
поделиться

Упрощенное решение. Используйте tempfile , чтобы создать временный файл, и если запись завершится успешно, просто переименуйте файл в исходный файл конфигурации.

Для блокировки файла см. portalocker .

3
ответ дан 1 December 2019 в 00:50
поделиться

Вы можете использовать модуль fileinput для обработки резервного копирования и записи на месте для вас:

import fileinput
for line in fileinput.input(filename,inplace=True, backup='.bak'):
    # inplace=True causes the original file to be moved to a backup
    # standard output is redirected to the original file.
    # backup='.bak' specifies the extension for the backup file.

    # manipulate line
    newline=process(line)
    print(newline)

Если вам нужно прочитать все содержимое, прежде чем вы сможете записать новую строку, тогда вы можете сначала сделать это, а затем распечатать все новое содержимое с помощью

newcontents=process(contents)
for line in fileinput.input(filename,inplace=True, backup='.bak'):
    print(newcontents)
    break

. Если сценарий завершается внезапно, у вас все еще будет резервная копия.

0
ответ дан 1 December 2019 в 00:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: