Exemple #1
0
        /// <summary>
        /// 打开文件进行读写,以将内存中的键值集合同步到文件中。
        /// 此方法保证跨进程/线程的安全执行。
        /// </summary>
        /// <param name="context">用于合并文件与内存中的键值集合。</param>
        /// <param name="lastWriteTime">文件的上一次修改时间。</param>
        /// <returns>修改了文件后,新的文件修改时间(如果内容不变,则时间也不变)。</returns>
        private DateTimeOffset SyncWhenFileHasBeenUpdated(ICriticalReadWriteContext <TKey, TValue> context, DateTimeOffset lastWriteTime)
        {
            // 在会打开文件流的地方自增。
            Interlocked.Increment(ref _fileSyncingCount);

            // 读取文件。
            var text = ReadAllText();

            _lastSyncedFileContent = text;

            // 将文件中的键值集合与内存中的键值集合合并。
            var newText = MergeFileTextAndKeyValueText(context, lastWriteTime, text,
                                                       out var updatedTime, out var hasChanged);

            // 将合并后的键值集合写回文件。
            if (hasChanged)
            {
                WriteAllText(newText);
                _lastSyncedFileContent = newText;
                return(updatedTime);
            }
            else
            {
                return(lastWriteTime);
            }
        }
Exemple #2
0
        /// <summary>
        /// 将内存中的键值集合同步到文件中,会根据键值的修改时间来修改文件的修改时间。
        /// 此方法保证跨进程/线程的安全执行。
        /// </summary>
        /// <param name="context">用于合并文件与内存中的键值集合。</param>
        private void SynchronizeCore(ICriticalReadWriteContext <TKey, TValue> context)
        {
            // 获取文件的外部更新时间。
            _file.Refresh();
            var utcNow        = DateTimeOffset.UtcNow;
            var lastWriteTime = _file.Exists ? FixFileTime(_file.LastWriteTimeUtc, utcNow) : utcNow;

            if (_file.Exists && _lastFileExists is false)
            {
                // 如果本此触发同步是因为文件新创建,那么无论此文件是新是旧,都视其为最新。
                // 我们认定,如果文件上次不存在而这次存在,即使文件时间是旧的(例如用户从回收站将其恢复),我们也应该视其为最新。
                lastWriteTime = utcNow;
            }
            DateTimeOffset newLastWriteTime;

            if (SupportsHighResolutionFileTime && lastWriteTime == _fileLastWriteTime && _file.Exists == _lastFileExists)
            {
                // 在支持高精度时间的文件系统上:
                // 自上次同步文件以来,文件从未发生过更改(无需提前打开文件)。
                CT.Log($"准备同步时,发现文件时间未改变 {_fileLastWriteTime.LocalDateTime:O}", _file.Name, "Sync");
                newLastWriteTime = SyncWhenFileHasNotBeenUpdated(context, lastWriteTime);
            }
            else
            {
                // 文件已经发生了更改。
                if (_file.Exists)
                {
                    if (SupportsHighResolutionFileTime)
                    {
                        CT.Log($"准备同步时({FileDriveFormat}),发现文件时间改变 {_fileLastWriteTime.LocalDateTime:O} -> {lastWriteTime.LocalDateTime:O}", _file.Name, "Sync");
                    }
                    else
                    {
                        CT.Log($"准备同步时,发现文件系统({FileDriveFormat ?? "null"})不支持高精度时间,强制完全同步 {lastWriteTime.LocalDateTime:O}", _file.Name, "Sync");
                    }
                }
                else
                {
                    CT.Log($"准备同步时,发现文件不存在", _file.Name, "Sync");
                }
                newLastWriteTime = SyncWhenFileHasBeenUpdated(context, lastWriteTime);
            }
            if (lastWriteTime != newLastWriteTime.UtcDateTime)
            {
                CT.Log($"正在更新文件时间 {lastWriteTime.LocalDateTime:O} -> {newLastWriteTime.LocalDateTime:O}", _file.Name, "Sync");
                _file.LastWriteTimeUtc = newLastWriteTime.UtcDateTime;
            }
            // 重新更新文件的信息,因为前面可能发生了更改。
            _lastFileExists    = _file.Exists;
            _fileLastWriteTime = _file.Exists ? newLastWriteTime : DateTimeOffset.MinValue;
        }
Exemple #3
0
        private string MergeFileTextAndKeyValueText(
            ICriticalReadWriteContext <TKey, TValue> context,
            DateTimeOffset lastWriteTime,
            string text,
            out DateTimeOffset updatedWriteTime, out bool hasChanged)
        {
            var externalKeyValues = _deserializer(text);
            var timedMerging      = context.MergeExternalKeyValues(externalKeyValues, lastWriteTime);
            var mergedKeyValues   = timedMerging.KeyValues.ToDictionary(x => x.Key, x => x.Value);
            var newText           = _serializer(mergedKeyValues);

            updatedWriteTime = timedMerging.Time;
            if (_fileEqualsComparison == FileEqualsComparison.KeyValueEquals)
            {
                hasChanged = !((ICollection <KeyValuePair <TKey, TValue> >)externalKeyValues).SequenceEqualsIgnoringOrder(mergedKeyValues);
            }
            else
            {
                hasChanged = !string.Equals(text, newText, StringComparison.Ordinal);
            }
            CT.Log($"合并键值集合:从文件 {{ {string.Join(", ", externalKeyValues.Keys)} }} 到新 {{ {string.Join(", ", mergedKeyValues.Keys)} }}", _file.Name, "Sync");
            return(newText);
        }