Форум программистов, компьютерный форум, киберфорум
PowerShell
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
57 / 9 / 4
Регистрация: 14.06.2013
Сообщений: 129
1

Создание файлов фиксированного размера (болванки файлов, dummy files)

09.10.2018, 18:10. Показов 1408. Ответов 14

Возникла необходимость создать несколько файлов фиксированного размера, в англоязычных источниках называемых dummy files. Для чего? Для тестирования дисковой системы, т.к. программы для теста обычно пишут-читают из файла создаваемого на разделе.

Возможно использование утилит в command prompt
Bash
1
2
FSUTIL.EXE file createnew c:\test\datafile.dat (1TB) 
FSUTIL.EXE file setvaliddata c:\test\datafile.dat (1TB)
Возможно использование PowerShell как указано в статье.

PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
function New-EmptyFile
{
   param( [string]$FilePath,[double]$Size )
 
   $file = [System.IO.File]::Create($FilePath)
   $file.SetLength($Size)
   $file.Close()
   Get-Item $file.Name
}
 
# Example.
$filepath = "c:\test\datafile.dat"
New-EmptyFile -FilePath $filepath -Size 4Gb

Что интересно, как пишут в описании утилиты FSUTIL, параметр setvaliddata устанавливает (???) некую "допустимую длину файла". На самом же деле setvaliddata делает содержимое файла отличное от NULL (см. скриншоты). Именно когда содержимое отлично от NULL возможно тестирование дисков, иначе показатели производительности сильно завышены, в общем не соответствуют действительности.

Возникает вопрос, как задать аналогично содержимое файла в PowerShell. Пока нашел только такую длинную функцию (источник), хотелось бы реализовать это короче, как в command prompt

PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
Function New-BigFile {
<#
.Synopsis
  Creates a large dummy file with or without random conntent
.DESCRIPTION
  Creates a large dummy file with or without random conntent 
  Credits for the randome content creation logic goes to Robert Robelo
.PARAMETER Target
   The full path to a folder or file. If the target is a folder a random file name is generated
.PARAMETER MegaByte
   The size of the random file to be genrated. Default is one MB
.PARAMETER Filecontent
  Possible values are <random> or <empty> When <random> is specified the file is filled with
  random values. The value <empty> fills the file with nulls. 
.PARAMETER ShowProgress
 This parameter is optional and shows the progress of the file creation. 
.EXAMPLE
 New-Bigfile -Target C:\Temp\LF -Megabyte 10 -Filecontent random
.EXAMPLE
 New-Bigfile -Target C:\Temp\LF\bigfile.txt -Megabyte 10 -Filecontent random
.EXAMPLE
 New-Bigfile -Target C:\Temp\LF -Megabyte 10 -Filecontent empty
#&gt;
 
[CmdletBinding(SupportsShouldProcess=$True)]
param(
    [Parameter(Mandatory = $true, Position = 0)]
    [String]$Target,
    [Parameter(Mandatory = $false, Position = 1)]
    [ValidateRange(1, 5120)]
    [UInt16]$MegaByte = 1,
    [Parameter(Mandatory = $true,position = 2)]
    [ValidateSet("random","empty")]
    [string]$FileContent,
    [Switch]$ShowProgress
)
 
 
If ([string]::IsNullOrEmpty([System.IO.Path]::GetDirectoryName("$target")) -eq $True)
{
    Write-Output "Specify a directory or file including path!"
    Throw
}
 
 
If([string]::IsNullOrEmpty([System.IO.Path]::GetExtension("$target")))
{
    Write-Verbose "Provided input $target has no file extension, target is a folder"
    $fname = ("" + ([guid]::NewGuid()) + ".LF")
    Write-Verbose "Random generated filename: $fname"
    $Target = Join-path $Target  $fname
    $folder = [System.IO.Path]::GetDirectoryName($target)
 
    If ((Test-path $folder) -eq $false)
    {If ($PSCmdlet.ShouldProcess("Directory does not exist, creating directory $folder ")) 
            { New-Item -Path $folder -ItemType Directory | Out-Null}}
}
Else
{
   If ((Test-path -Path $target) -eq $true)
        {Write-verbose "File $Target already exists, exiting to prevent overwrite"
        Break}
    Else
        {Write-Verbose "File $target does not exist yet"}
 
    # Check if the directory actually exists, if not create it
    $folder = [System.IO.Path]::GetDirectoryName($target)
    If ((Test-path $folder) -eq $false)
    {If ($PSCmdlet.ShouldProcess("Creating folder $folder")) 
            {New-Item -Path $folder -ItemType Directory | Out-Null}}
}
 
$path = $Target
$total = 1mb * $MegaByte
$strings = $bytes = 0
 
If ($FileContent -eq "random")
{
If ($PSCmdlet.ShouldProcess("Creating random file $path with $Megabyte MB")) 
{
 
# create the stream writer
$sw = New-Object IO.streamWriter $path
 
# get a 64 element Char[]; I added the - and _ to have 64 chars
[char[]]$chars = 'azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789-_'
1..$MegaByte | ForEach-Object {
# get 1MB of chars from 4 256KB strings
1..4 | ForEach-Object {
# randomize all chars and...
$rndChars = $chars | Get-Random -Count $chars.Count
# ...join them in a string
$str = -join $rndChars
# repeat random string 4096 times to get a 256KB string
$str_ = $str * 4kb
# write 256KB string to file
$sw.Write($str_)
# show progress
 
    if ($ShowProgress) {
    $strings++
    $bytes += $str_.Length
    Write-Progress -Activity "Writing String #$strings" -Status "$bytes Bytes written" -PercentComplete ($bytes / $total * 100)
    }
 
# release resources by clearing string variables
Clear-Variable str, str_
}
}
$sw.Close()
$sw.Dispose()
# release resources through garbage collection
[GC]::Collect()
}
}
 
Else 
{
    If ($PSCmdlet.ShouldProcess("Creating empty file $path with $Megabyte MB")) 
    {
    # write 4K worth of data at a time
    $bufSize = 4096
    $bytes = New-Object byte[] $bufSize
    $file = [System.IO.File]::Create("$path")
    # write the first block out to accommodate integer division truncation
    $file.Write($bytes, 0, $bufSize)
    for ($i = 0; $i -lt $Megabyte*1MB; $i = $i + $bufSize) { $file.Write($bytes, 0, $bufSize) 
 
    if ($ShowProgress) {
        Write-Progress -Activity "Writing String #$strings" -Status "Bytes written" -PercentComplete ($i/($megabyte*1MB)*100 )
    }
    }
    $file.Close()
} 
} 
} 
 
# Example.
 
New-bigfile c:\temp\lf\dummy10mb.txt 10 random  -Verbose
0
Миниатюры
Создание файлов фиксированного размера (болванки файлов, dummy files)   Создание файлов фиксированного размера (болванки файлов, dummy files)  
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.10.2018, 18:10
Ответы с готовыми решениями:

Проверка существования файлов, создание файлов и вывод содержимого файлов на принтер
Создать BAT-файл который поддерживает создание файлов проверку их и вывод на принтер. Как это...

ProgressBar для отображения процесса удаления файлов (с учетом размера файлов)
Есть папки, которые периодически заполняются ненужными файлами. Нужно создать прогрессБар на каждую...

Работа с файловой системой. Поиск файлов, определение размеров файлов и подсчёт среднего арифметического размера.
Всем привет! Помогите пожалуйста! Вообщем необходимо реализовать программу , которая будет...

Создание списка файлов конечного размера в котором старые файлы удаляются
Доброго времени суток! Не могу найти информацию о том как создать список из файлов в котором...

__________________

Записывайтесь на профессиональные курсы DevOps-инженеров
14
57 / 9 / 4
Регистрация: 14.06.2013
Сообщений: 129
09.10.2018, 18:22  [ТС] 2
Т.е. по сути вопрос в том, как просто создать болванку файла случайного содержания в PowerShell. Command prompt насколько понимаю, использует какие-то особенности файловой системы, не прибегая к генератору случайных чисел.
0
2565 / 1846 / 401
Регистрация: 11.09.2009
Сообщений: 6,860
09.10.2018, 18:24 3
Цитата Сообщение от xlxndr Посмотреть сообщение
Для тестирования дисковой системы
Переписывать что-то в файле функциями для работы с файлами, "для тестирования дисковой системы" абсолютно бессмысленно, так как все изменения каждый раз будут записаны физически на диске на новом месте.
0
1877 / 1102 / 425
Регистрация: 22.01.2016
Сообщений: 3,050
09.10.2018, 18:25 4
Цитата Сообщение от xlxndr Посмотреть сообщение
хотелось бы реализовать это короче
Вот это пробовали - Fastest Way to Create a File With Random Data?
1
2565 / 1846 / 401
Регистрация: 11.09.2009
Сообщений: 6,860
09.10.2018, 18:28 5
delete
0
57 / 9 / 4
Регистрация: 14.06.2013
Сообщений: 129
10.10.2018, 15:50  [ТС] 6
Похоже на то, что нужно... Но
1. таким методом в powershell возможно генерировать массивы byte[] меньше 2GB.
2. массив полностью выгружается в память, в отличае от FSUTIL.EXE file setvaliddata (можно убедиться в диспетчере задач).

PowerShell
1
2
3
4
5
6
$filename = "C:\test\testfile.dat"
$bytes = 4Mb
[System.Security.Cryptography.RNGCryptoServiceProvider] $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
$rndbytes = New-Object byte[] $bytes
$rng.GetBytes($rndbytes)
[System.IO.File]::WriteAllBytes($filename, $rndbytes)
0
1877 / 1102 / 425
Регистрация: 22.01.2016
Сообщений: 3,050
10.10.2018, 16:00 7
Цитата Сообщение от xlxndr Посмотреть сообщение
таким методом в powershell возможно генерировать массивы byte[] меньше 2GB.
Создайте в цикле 500 файлов, вот вам и 1TB занятых на диске, а ещё можно все их собрать в один
0
57 / 9 / 4
Регистрация: 14.06.2013
Сообщений: 129
10.10.2018, 16:08  [ТС] 8
Это понятно, можно просто скачать фильм с торрента размером 4Gb - вот и готовый файл... )
Просто эти методы хардкорны... и понимания как это работает не дают. Не понятно, каким образом FSUTIL.EXE file setvaliddata моментально изменяет данные в файле размером 4Gb... если это проводить через оперативную память, то процесс займет хотя бы 10 сек... но нет... FSUTIL отрабатывает моментально...
0
1877 / 1102 / 425
Регистрация: 22.01.2016
Сообщений: 3,050
10.10.2018, 17:07 9
Цитата Сообщение от xlxndr Посмотреть сообщение
Не понятно, каким образом FSUTIL.EXE file setvaliddata моментально изменяет данные в файле размером 4Gb... если это проводить через оперативную память, то процесс займет хотя бы 10 сек... но нет... FSUTIL отрабатывает моментально...
MS пишут:

Writing raw clusters directly to disk through a hardware channel. This allows the program to inform the file system that this range contains valid data that can be returned to the user.
Т.е. прямая запись на уровне кластеров.

Не по теме:

А вот как это реализовано, наверно не лучшая идея, спрашивать в разделе по скриптовому языку, который работает на основе высокоуровневого фреймворка :)

1
3432 / 1422 / 239
Регистрация: 10.12.2013
Сообщений: 4,883
10.10.2018, 17:17 10
Цитата Сообщение от xlxndr Посмотреть сообщение
Не понятно, каким образом FSUTIL.EXE file setvaliddata моментально изменяет данные в файле размером 4Gb
Предполагаю, что это не файл с реальными данными, а sparse file
1
Эксперт Python
4473 / 3260 / 1055
Регистрация: 28.10.2013
Сообщений: 8,394
Записей в блоге: 1
10.10.2018, 20:19 11
Цитата Сообщение от xlxndr Посмотреть сообщение
Command prompt насколько понимаю, использует какие-то особенности файловой системы
fsutil - да. setfilevaliddata это не просто опция fsutil - это реальная функция ОС.
И она сильно отличается от обычных WinAPI функций, которые при выделении кластеров под файл заполняют их значением NULL из соображений конфиденцильности.

Функция SetFileValidData позволяет не заполнять данные нулями при записи непоследовательно в файл. (перевод сделан Mr. Online Translator :-))
Typically, the SetFileValidData function is used by system-level applications on their own private data.
Not all file systems use valid data length. Some file systems can track multiple valid data ranges.
In general, most applications will never need to call this function.
The SetFileValidData function allows you to avoid filling data with zeros when writing nonsequentially to a file.
The function makes the data in the file valid without writing to the file.
As a result, although some performance gain may be realized, existing data on disk from previously existing files can inadvertently become available to unintended readers.

Все данные там - это мусор от как бы удаленных пользователем файлов.
Вы же вы курсе, что реально с диска данные не удаляются (ну если, конечно, вы каким-нить шредером не пройдетесь), а просто их место в $MFT\$bitmap помечается как "незанятое"?

На а sparse файлы с NULL - это вообще фикция, обманка ОС.
Sparse Files NTFS позволяют приложениям создавать очень большие файлы, состоящие в основном из нулевых диапазонов, без фактического выделения LCN (логических кластеров) для нулевых диапазонов.
1
57 / 9 / 4
Регистрация: 14.06.2013
Сообщений: 129
18.10.2018, 17:50  [ТС] 12
Попробовал разобраться с SetFileValidData(). Результат: файл заполненный NULL остался заполненным NULL, никаких "мусорных" данных как ожидалось, не появилось!

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Runtime.InteropServices;
 
namespace My
{
    class Progmam
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool SetFileValidData(SafeFileHandle hFile, long ValidDataLength);
 
    }
    static void Main(string[] args)
    {
        using (var fstream = File.Open(@"C:\test\test1.dat", FileMode.Open, FileAccess.ReadWrite))
        {
            Progmam.SetFileValidData(fstream.SafeFileHandle, 4000);
        }
    }
}
0
2565 / 1846 / 401
Регистрация: 11.09.2009
Сообщений: 6,860
18.10.2018, 23:15 13
Цитата Сообщение от xlxndr Посмотреть сообщение
файл заполненный NULL остался заполненным NULL
Естественно. Эта функция потому и работает быстро, что ничего не заполняет. Даже по её названию понятно - данные, уже имеющиеся на диске, считать правильными.
0
Эксперт Python
4473 / 3260 / 1055
Регистрация: 28.10.2013
Сообщений: 8,394
Записей в блоге: 1
19.10.2018, 02:01 14
Просто процитирую (источник обсуждения можно нагуглить), чтобы не размазывать манную кашу по столу:
без SetFilePointer и SetEndOfFile функция будет работать только если ты откроешь заранее созданный файл достаточного размера, чтобы он покрывал размер, передаваемый в SetFileValidData
в остальных случаях SetFilePointer и SetEndOfFile обязательны
1. создай новый файл
2. сдвинь указатель на 64Гб
3. укажи конец файла
4. вызови SetFileValidData с размером в 64 кб
P.S. SetEndOfFile указывает физический конец файла. SetFileValidData - логический конец, то есть диапазон который можно читать. Диапазон между логическим и физическим концом называется хвостом файла и при попытках чтения хвоста будет всегда возвращаться NULL.
В стандартных случаях создания и чтения у файлов нет хвостов, так как граница логическая совпадает с физической.
2
95 / 16 / 5
Регистрация: 05.07.2015
Сообщений: 49
25.10.2018, 12:57 15
Стало интересно создание такого файла функцией powershell, к сожалению в ветке не нашел готовый код. Получилось сделать используя только SetFileValidData, может что не правильно, но работает.
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function New-EmptyFile
{
   param( 
    [string]$FilePath,
    [double]$Size,
    [switch]$SetFileValidData
   
   )
   if (-not ("MyOperationFile.File" -as [type] )) {
   
       Add-Type  -Namespace MyOperationFile -Name File  -UsingNamespace "Microsoft.Win32.SafeHandles" -MemberDefinition @'
 
           [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
           public static extern bool SetFileValidData(SafeFileHandle hFile, long ValidDataLength);
 
 
'@
 
   } 
   $file = [System.IO.File]::Create($FilePath)
   $file.SetLength($Size)
   if ($SetFileValidData) {
        [MyOperationFile.File]::SetFileValidData($file.SafeFileHandle, $file.length)
   }
   $file.Close()
   Get-Item $file.Name
}
 
 
 return
 
# Example.
$filepath = "e:\new_empty1.dat" 
$filepath | ? { Test-Path $_ } | % { ri $_ -Verbose }
New-EmptyFile -FilePath $filepath -Size 1gb -SetFileValidData
 
 
$f = (gi $filepath).Open([system.io.filemode]::OpenOrCreate)
$f.Position = $f.Length - 1kb
 $i = 1
 do {
    "$i`: " + $f.ReadByte()
    $i++
 
 } while ( $f.Position -lt ($f.Length) ) 
 $f.Close()
 
 $f.Name | ri -Verbose
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.10.2018, 12:57

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Создание папок по цифровому названию файлов и перенос этих файлов в созданные папки
Доброго времени суток. Необходим БАТ файл. Что имеем: Общую папку с файлами типа...

Создание папок с именами заданных файлов и перемещение этих файлов в созданные папки
Подскажите пожалуйста как по названиям файлов txt создать папки и положить в каждую из папок файл с...

Поиск на диске файлов с расширениями .txt и .docx и создание списка имён найденных файлов
Помогите, нужно создать bat файл, который ищет на диске файлы *.txt *docx а потом создаёт список с...

Сравнение файлов в папке и создание папок с именами файлов
Нужно пройтись по папке, если есть картинка с названием, но нет папки с таким же названием, создать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.