1
0

migration

This commit is contained in:
2025-04-29 22:08:00 +03:00
commit ad28507008
232 changed files with 12299 additions and 0 deletions

View File

@ -0,0 +1,5 @@
Викладач: Мельникова Р. В.
Оцінка: 92
Додатково:
Виконував в команді.

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,694 @@
// Academic aliases {{{1
/// subject abbreviations to full names
#let subjects = (
"БД": "Бази даних",
"ОПНJ": "Основи програмування на Java",
"ОС": "Операційні системи",
"ПП": "Проектний практикум",
"СПМ": "Скриптові мови програмування",
"Ф": "Філософія",
)
/// education program abbreviations to name & number
#let edu_programs = (
"ПЗПІ": (
name: "Інженерія програмного забезпечення",
number: 121, // TODO: ПЗПІ is "F2" now
),
)
// Template formatting functions {{{1
/// numberless heading
#let nheading(title) = heading(depth: 1, numbering: none, title)
/// fill horizontal space with a box and not an empty space
#let hfill(width) = box(width: width, repeat("")) // NOTE: This is a HAIR SPACE (U+200A), not a regular space
/// make underlined cell with filled value
#let uline(align: center, content) = underline[
#if align != left { hfill(1fr) }
#content
#if align != right { hfill(1fr) }
]
/// bold text
#let bold(content) = text(weight: "bold")[#content]
/// month name from its number
#let month_gen(month) = (
"січня",
"лютого",
"березня",
"квітня",
"травня",
"червня",
"липня",
"серпня",
"вересня",
"жовтня",
"листопада",
"грудня",
).at(month - 1)
// Helper functions {{{1
/// captioned image with label derived from path:
/// - "image.png" = @image
/// - "img/image.png" = @image
/// - "img/foo/image.png" = @foo_image
/// - "img/foo/foo_image.png" = @foo_image
/// the caption will be modified based on a conditional positional value:
/// - `none`: no change
/// - some value: "`caption` (за даними `value`)"
/// - no value: "`caption` (рисунок виконано самостійно)"
/// additional named arguments will be passed to original `image` function
#let img(path, caption, ..sink) = {
let parts = path.split(".").first().split("/")
let label_string = if parts.len() <= 2 or parts.at(-1).starts-with(parts.at(-2)) {
// ("image",), (_, "image") and (.., "img", "img_image")
parts.last()
} else {
// (.., "img", "image") = "img_image"
parts.at(-2) + "_" + parts.at(-1)
}.replace(" ", "_")
let caption = if sink.pos().len() == 0 {
caption + " (рисунок виконано самостійно)"
} else if sink.pos().first() == none {
caption
} else {
[#caption (за даними #sink.pos().first())]
}
[#figure(image(path, ..sink.named()), caption: caption) #label(label_string)]
}
// Styling {{{1
/// NOTE: may be wrong
#let ua_alpha_numbering = "абвгдежиклмнпрстуфхцшщюя".split("") // 0 = "", 1 = "а"
// general outlook {{{2
// spacing between lines
#let spacing = 0.95em
#let style(it) = {
set page(
paper: "a4",
margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm),
number-align: top + right,
numbering: (..numbers) => {
if numbers.pos().at(0) != 1 {
numbering("1", numbers.pos().at(0))
}
},
)
set text(font: ("Times New Roman", "Liberation Serif"), size: 14pt, hyphenate: false, lang: "uk")
set par(justify: true, first-line-indent: (amount: 1.25cm, all: true))
set underline(evade: false)
// set 1.5 line spacing
set block(spacing: spacing)
set par(spacing: spacing)
set par(leading: spacing)
// enums and lists {{{2
set enum(numbering: i => { ua_alpha_numbering.at(i) + ")" }, indent: 1.25cm, body-indent: 0.5cm)
show enum: it => {
set enum(indent: 0em, numbering: "1)")
it
}
set list(indent: 1.35cm, body-indent: 0.5cm, marker: [--])
// figures {{{2
show figure: it => {
v(spacing * 2, weak: true)
it
v(spacing * 2, weak: true)
}
set figure.caption(separator: [ -- ])
show figure.where(kind: table): set figure.caption(position: top)
show figure.caption.where(kind: table): set align(left)
// figure numbering
show heading.where(level: 1): it => {
counter(math.equation).update(0)
counter(figure.where(kind: image)).update(0)
counter(figure.where(kind: table)).update(0)
counter(figure.where(kind: raw)).update(0)
it
}
set math.equation(numbering: (..num) => numbering("(1.1)", counter(heading).get().at(0), num.pos().first()))
set figure(numbering: (..num) => numbering("1.1", counter(heading).get().at(0), num.pos().first()))
// appearance of references to images and tables {{{2
set ref(
supplement: it => {
if it == none or not it.has("kind") {
it
} else if it.kind == image {
"див. рис."
} else if it.kind == table {
"див. таблицю"
} else {
it
}
},
)
show ref: it => {
let el = it.element
if el == none or not el.has("kind") {
return it
}
if el.kind != image and el.kind != table {
return it
}
[(#it)]
}
// headings {{{2
set heading(numbering: "1.1")
show heading.where(level: 1): it => {
set align(center)
set text(size: 14pt, weight: "semibold")
pagebreak(weak: true)
upper(it)
v(spacing * 2, weak: true)
}
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
show heading.where(level: 3): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
it
}
// Coursework template {{{1
/// DSTU 3008:2015 Template for NURE
/// -> content
/// - doc (content): Content to apply the template to.
/// - title (str): Title of the document.
/// - subject_shorthand (str): Subject short name.
/// - department_gen (str): Department name in genitive form.
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
/// - mentors ((name: str, gender: str, degree: str),): List of mentors dicts.
/// - edu_program_shorthand (str): Education program shorthand.
/// - task_list (done_date: datetime, initial_date: datetime, source: (content | str), content: (content | str), graphics: (content | str)): Task list object.
/// - calendar_plan ( plan_table: (content | str), approval_date: datetime): Calendar plan object.
/// - abstract (keywords: (str, ), text: (content | str)): Abstract object.
/// - bib_path path: Path to the bibliography yaml file.
/// - appendices (content): Content with appendices.
#let cw-template(
doc,
title: "NONE",
subject_shorthand: "NONE",
department_gen: "Програмної інженерії",
author: (),
mentors: (),
edu_program_shorthand: "ПЗПІ",
task_list: (),
calendar_plan: (),
abstract: (),
bib_path: "bibl.yml",
appendices: (),
) = {
set document(title: title, author: author.name)
show: style
let bib-count = state("citation-counter", ())
show cite: it => {
it
bib-count.update(((..c)) => (..c, it.key))
}
show bibliography: it => {
set text(size: 0pt)
it
}
let head_mentor = mentors.at(0)
let edu_program = edu_programs.at(edu_program_shorthand)
// page 1 {{{2
[
#set align(center)
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
\
Кафедра Програмної інженерії
\
ПОЯСНЮВАЛЬНА ЗАПИСКА
ДО КУРСОВОЇ РОБОТИ
з дисципліни: "#subjects.at(subject_shorthand, default: "NONE")"
Тема роботи: "#title"
\ \ \
#columns(2, gutter: 4cm)[
#set align(left)
#if author.gender == "m" { [Виконав\ ] } else { [Виконала\ ] } ст. гр. #author.group
\
Керівник:\
#head_mentor.degree
\
Робота захищена на оцінку
\
Комісія:\
#for mentor in mentors {
[#mentor.degree\
]
}
#colbreak()
#set align(left)
\
#author.name
\ \
#head_mentor.name
\
#underline(" " * 35)
\ \
#for mentor in mentors {
[#mentor.name\
]
}
]
#v(1fr)
Харків -- #task_list.done_date.display("[year]")
#pagebreak()
]
// page 2 {{{2
{
uline[Харківський національний університет радіоелектроніки]
linebreak()
linebreak()
grid(
columns: (100pt, 1fr),
bold[
Кафедра
Дисципліна
Спеціальність
],
{
uline(align: left, department_gen)
linebreak()
uline(align: left, subjects.at(subject_shorthand))
linebreak()
uline(align: left, [#edu_program.number #edu_program.name])
},
)
grid(
columns: (1fr, 1fr, 1fr),
gutter: 0.3fr,
[#bold[Курс] #uline(2)], [#bold[Група] #uline(author.group)], [#bold[Семестр] #uline(3)],
)
linebreak()
linebreak()
linebreak()
align(center, bold[ЗАВДАННЯ \ на курсову роботу студента])
linebreak()
uline(align: left)[_#author.full_name_gen _]
linebreak()
linebreak()
bold[\1. Тема роботи:]
uline[#title.]
linebreak()
{
bold[\2. Строк здачі закінченої роботи:]
uline(task_list.done_date.display("[day].[month].[year]"))
hfill(10fr)
}
linebreak()
bold[\3. Вихідні дані для роботи:]
uline(task_list.source)
linebreak()
bold[\4. Зміст розрахунково-пояснювальної записки:]
uline(task_list.content)
linebreak()
bold[\5. Перелік графічного матеріалу:]
uline(task_list.graphics)
linebreak()
{
bold[\6. Дата видачі завдання:]
uline(task_list.initial_date.display("[day].[month].[year]"))
hfill(10fr)
}
pagebreak()
}
// page 3 {{{2
{
align(center, bold[КАЛЕНДАРНИЙ ПЛАН])
set par(first-line-indent: 0pt)
linebreak()
calendar_plan.plan_table
linebreak()
grid(
columns: (5fr, 5fr),
grid(
columns: (1fr, 2fr, 1fr),
gutter: 0.2fr,
[
Студент \
Керівник \
#align(center)["#underline[#calendar_plan.approval_date.day()]"]
],
[
#uline(align: center, []) \
#uline(align: center, []) \
#uline(align: center, month_gen(calendar_plan.approval_date.month()))
],
[
\ \
#underline[#calendar_plan.approval_date.year()] р.
],
),
[
#author.name, \
#head_mentor.degree
#head_mentor.name.
],
)
pagebreak()
}
// page 4 {{{2
[
#align(center, bold[РЕФЕРАТ]) \
#context [
#let pages = counter(page).final().at(0)
#let images = query(figure.where(kind: image)).len()
#let tables = query(figure.where(kind: table)).len()
#let bibs = bib-count.final().dedup().len()
/* TODO: why this stopped working?
#let tables = counter(figure.where(kind: table)).final().at(0)
#let images = counter(figure.where(kind: image)).final().at(0)*/
#let counters = ()
#if pages != 0 { counters.push[#pages с.] }
#if tables != 0 { counters.push[#tables табл.] }
#if images != 0 { counters.push[#images рис.] }
#if bibs != 0 { counters.push[#bibs джерел] }
Пояснювальна записка до курсової роботи: #counters.join(", ").
]
\
#{
let keywords = abstract.keywords.map(upper)
let is_cyrillic = word => word.split("").any(char => ("А" <= char and char <= "я"))
let n = keywords.len()
for i in range(n) {
for j in range(0, n - i - 1) {
if (
(not is_cyrillic(keywords.at(j)) and is_cyrillic(keywords.at(j + 1)))
or (
is_cyrillic(keywords.at(j)) == is_cyrillic(keywords.at(j + 1)) and keywords.at(j) > keywords.at(j + 1)
)
) {
(keywords.at(j), keywords.at(j + 1)) = (keywords.at(j + 1), keywords.at(j))
}
}
}
keywords.join(", ")
}
\
#abstract.text
]
// page 5 {{{2
outline(
title: [
ЗМІСТ
#v(spacing * 2, weak: true)
],
depth: 2,
indent: auto,
)
doc
// bibliography {{{2
{
heading(depth: 1, numbering: none)[Перелік джерел посилання]
bibliography(
bib_path,
style: "ieee",
full: true,
title: none,
)
let bib_data = yaml(bib_path)
let format-entry(citation) = {
if (citation.type == "Web") {
let date_array = citation.url.date.split("-")
let date = datetime(
year: int(date_array.at(0)),
month: int(date_array.at(1)),
day: int(date_array.at(2)),
)
[
#citation.title.
#citation.author.
URL: #citation.url.value (дата звернення: #date.display("[day].[month].[year]")).
]
} else if citation.type == "Book" [
#citation.author
#citation.title.
#citation.publisher,
#citation.date.
#citation.page-total c.
] else [
UNSUPPORTED BIBLIOGRAPHY ENTRY TYPE, PLEASE OPEN AN ISSUE
]
}
show enum.item: it => {
set par(first-line-indent: 0pt)
box(width: 1.25cm)
box(width: 1em + 0.5cm)[#it.number.]
it.body
linebreak()
}
context {
for (i, citation) in query(ref.where(element: none)).map(r => str(r.target)).dedup().enumerate() {
enum.item(
i + 1,
format-entry(bib_data.at(citation)),
)
}
}
}
// appendices {{{2
{
counter(heading).update(0)
set heading(
numbering: (i, ..nums) => {
let char = upper(ua_alpha_numbering.at(i))
if nums.pos().len() == 0 { char } else {
char + "." + nums.pos().map(str).join(".")
}
},
)
show heading.where(level: 1): it => {
set align(center)
set text(size: 14pt, weight: "regular")
pagebreak(weak: true)
bold[ДОДАТОК #counter(heading).display(it.numbering)]
linebreak()
it.body
v(spacing * 2, weak: true)
}
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
appendices
}
}
// Laboratory work template {{{1
/// DSTU 3008:2015 Template for NURE
/// -> content
/// - doc (content): Content to apply the template to.
/// - doctype ("ЛБ" | "ПЗ"): Document type.
/// - title (str): Title of the document.
/// - subject_shorthand (str): Subject short name.
/// - department_gen (str): Department name in genitive form.
/// - worknumber (int): Number of the work, can be omitted.
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
/// - mentor (name: str, gender: str, degree: str): Mentors objects.
#let lab-pz-template(
doc,
doctype: "NONE",
title: "NONE",
subject_shorthand: "NONE",
department_gen: "Програмної інженерії",
worknumber: 1,
authors: (),
mentor: (),
) = {
set document(title: title, author: authors.at(0).name)
show: style
context counter(heading).update(worknumber - 1)
// page 1 {{{2
align(center)[
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ \
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
\ \
Кафедра #department_gen
\ \ \
Звіт \
з
#if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи]
#if worknumber != none [ #worknumber]
з дисципліни: "#subjects.at(subject_shorthand, default: "UNLNOWN SUBJECT, PLEASE OPEN AN ISSUE")"
з теми: "#title"
\ \ \ \
#columns(2)[
#set align(left)
#set par(first-line-indent: 0pt)
#if authors.len() == 1 {
let author = authors.at(0)
if author.gender == "m" [Виконав:\ ] else [Виконала:\ ]
[
ст. гр. #author.group\
#author.name\
]
if author.variant != none [Варіант: #author.variant]
} else [
Виконали:\
ст. гр. #authors.at(0).group\
#for author in authors {
[#author.name \ ]
}
]
#colbreak()
#set align(right)
#if mentor.gender == "m" { [Перевірив:\ ] } else { [Перевірила:\ ] }
#mentor.degree #if mentor.degree.len() >= 15 [\ ]
#mentor.name\
]
#v(1fr)
Харків -- #datetime.today().display("[year]")
]
pagebreak(weak: true)
heading(title)
doc
}
// vim:sts=2:sw=2:fdl=0:fdm=marker:cms=/*%s*/

View File

@ -0,0 +1,17 @@
CompileFlags:
Add: [-Wall, -Wextra, -std=c++17, -DBUILD_SHARED, --target=x86_64-w64-mingw32]
CompilationDatabase: build/
Diagnostics:
UnusedIncludes: Strict
InlayHints:
Enabled: Yes
ParameterNames: Yes
DeducedTypes: Yes
Index:
Background: Build
Hover:
ShowAKA: Yes

View File

@ -0,0 +1,23 @@
CC = x86_64-w64-mingw32-g++
CXXFLAGS = -std=c++23 -I/usr/x86_64-w64-mingw32/include -Iinclude -static
LDFLAGS = -lstdc++exp
SOURCES = main.cpp $(wildcard src/*.cpp)
TARGET = build/main.exe
.PHONY: all build run clean
all: build run
build: clean $(TARGET)
$(TARGET): $(SOURCES)
@mkdir -p build
@$(CC) $(CXXFLAGS) -o $(TARGET) $(SOURCES) $(LDFLAGS)
run: $(TARGET)
@WINEDEBUG=fixme-all wine $(TARGET)
clean:
@rm -rf build
@rm -rf ../files_moved

View File

@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <vector>
#include "IFileSystemEntity.h"
namespace System::IO {
class Directory : public IFileSystemEntity {
private:
std::wstring path;
public:
explicit Directory(const std::wstring& directoryPath);
~Directory() override = default;
std::wstring GetPath() const override;
DWORD GetAttributes() const override;
bool SetAttributes(DWORD attributes) override;
static bool Exists(const std::wstring& path);
static bool CreateDirectory(const std::wstring& path);
static bool Delete(const std::wstring& path);
static bool Move(const std::wstring& source, const std::wstring& destination);
static std::vector<std::wstring> GetFiles(const std::wstring& path);
static std::vector<std::wstring> GetDirectories(const std::wstring& path);
};
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <string>
#include <vector>
#include <cstdint>
namespace System::IO {
enum class DriveType : unsigned int {
Unknown = 0,
NoRootDir = 1,
Removable = 2,
Fixed = 3,
Remote = 4,
CDROM = 5,
RAM = 6
};
class DriveInfo {
public:
explicit DriveInfo(const std::wstring& path);
std::wstring Name;
DriveType DriveType;
std::wstring DriveFormat;
uint64_t TotalSize;
uint64_t AvailableFreeSpace;
bool IsReady;
static std::vector<DriveInfo> GetDrives();
private:
std::wstring rootPath;
};
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <cstdint>
#include <string>
#include "IFileSystemEntity.h"
namespace System::IO {
class File : public IFileSystemEntity {
private:
std::wstring path;
public:
explicit File(const std::wstring &filePath);
~File() override = default;
std::wstring GetPath() const override;
static DWORD GetAttributes(const std::wstring &path);
static bool SetAttributes(const std::wstring &path, DWORD attributes);
static bool Exists(const std::wstring &path);
static bool Copy(const std::wstring &source, const std::wstring &destination,
bool overwrite = false);
static bool Delete(const std::wstring &path);
static bool Move(const std::wstring &source, const std::wstring &destination);
static uint64_t GetSize(const std::wstring &path);
};
} // namespace System::IO

View File

@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <windows.h>
namespace System::IO {
class FileStream {
private:
HANDLE hFile;
std::wstring path;
public:
FileStream(const std::wstring& filePath,
DWORD access,
DWORD creationDisposition,
DWORD shareMode = 0,
DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL);
~FileStream();
bool Read(void* buffer, DWORD numBytesToRead, DWORD& numBytesRead);
bool Write(const void* buffer, DWORD numBytesToWrite, DWORD& numBytesWritten);
bool Seek(LARGE_INTEGER offset, DWORD moveMethod, ULARGE_INTEGER& newPos);
bool SetEnd();
HANDLE GetHandle() const { return hFile; }
std::wstring GetPath() const { return path; }
};
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <string>
#include <windows.h>
namespace System::IO {
class IFileSystemEntity {
public:
virtual std::wstring GetPath() const = 0;
virtual DWORD GetAttributes() const = 0;
virtual bool SetAttributes(DWORD attributes) = 0;
virtual ~IFileSystemEntity() = default;
};
}

View File

@ -0,0 +1,112 @@
#include <chrono>
#include <cstring>
#include <iostream>
#include <vector>
#include "include/System/IO/Directory.h"
#include "include/System/IO/DriveInfo.h"
#include "include/System/IO/File.h"
#include "include/System/IO/FileStream.h"
using namespace System::IO;
int main() {
const std::wstring filesDir = L"../files";
const std::wstring filePath = filesDir + L"/bigfile.dat";
const std::wstring copyPath = filesDir + L"/bigfile_copy.dat";
const std::wstring movedCopyPath = filesDir + L"/moved_bigfile_copy.dat";
const std::wstring movedDirPath = L"../files_moved";
const size_t blockSize = 1024 * 1024; // 1 MB
const int32_t iterations = 100; // 100 MB file
if (!Directory::Exists(filesDir))
Directory::CreateDirectory(filesDir);
std::vector<char> buffer(blockSize, 'A');
DWORD bytesWritten = 0;
auto startWrite = std::chrono::high_resolution_clock::now();
{
FileStream outStream(filePath, GENERIC_WRITE, CREATE_ALWAYS);
for (int32_t i = 0; i < iterations; i++)
outStream.Write(buffer.data(), static_cast<DWORD>(buffer.size()),
bytesWritten);
}
auto endWrite = std::chrono::high_resolution_clock::now();
std::wcout << L"C++ Write time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
endWrite - startWrite)
.count()
<< L" ms" << std::endl;
auto startCopy = std::chrono::high_resolution_clock::now();
File::Copy(filePath, copyPath, true);
auto endCopy = std::chrono::high_resolution_clock::now();
std::wcout << L"C++ Copy time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(endCopy -
startCopy)
.count()
<< L" ms" << std::endl;
auto startRead = std::chrono::high_resolution_clock::now();
{
FileStream inStream(filePath, GENERIC_READ, OPEN_EXISTING);
std::vector<char> readBuffer(blockSize);
DWORD bytesRead = 0;
while (inStream.Read(readBuffer.data(),
static_cast<DWORD>(readBuffer.size()), bytesRead) &&
bytesRead > 0) {
}
}
auto endRead = std::chrono::high_resolution_clock::now();
std::wcout << L"C++ Read time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(endRead -
startRead)
.count()
<< L" ms" << std::endl;
auto startAttr = std::chrono::high_resolution_clock::now();
DWORD attrs = File::GetAttributes(filePath);
File::SetAttributes(filePath, attrs | FILE_ATTRIBUTE_HIDDEN);
File::SetAttributes(filePath, attrs);
auto endAttr = std::chrono::high_resolution_clock::now();
std::wcout << L"File attribute toggle time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(endAttr -
startAttr)
.count()
<< L" ms" << std::endl;
auto startMoveFile = std::chrono::high_resolution_clock::now();
File::Move(copyPath, movedCopyPath);
auto endMoveFile = std::chrono::high_resolution_clock::now();
std::wcout << L"Move file time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
endMoveFile - startMoveFile)
.count()
<< L" ms" << std::endl;
if (!Directory::Exists(movedDirPath))
Directory::CreateDirectory(movedDirPath);
auto startMoveDir = std::chrono::high_resolution_clock::now();
Directory::Move(filesDir, movedDirPath + L"/files");
auto endMoveDir = std::chrono::high_resolution_clock::now();
std::wcout << L"Move directory time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
endMoveDir - startMoveDir)
.count()
<< L" ms" << std::endl;
std::wcout << L"Listing drives:\n";
auto fixedDrives = DriveInfo::GetDrives();
for (const auto &d : fixedDrives) {
if (d.IsReady && d.DriveType == DriveType::Fixed &&
d.DriveFormat != L"squashfs") {
std::wcout << L"Drive: " << d.Name << L" | Type: "
<< static_cast<UINT>(d.DriveType) << L" | Format: "
<< d.DriveFormat << L" | Total: "
<< d.TotalSize / (1024 * 1024) << L" MB" << L" | Free: "
<< d.AvailableFreeSpace / (1024 * 1024) << L" MB\n";
}
}
}

View File

@ -0,0 +1,69 @@
#include <windows.h>
#include "../include/System/IO/Directory.h"
namespace System::IO {
Directory::Directory(const std::wstring& directoryPath) : path(directoryPath) { }
std::wstring Directory::GetPath() const {
return path;
}
DWORD Directory::GetAttributes() const {
return GetFileAttributesW(path.c_str());
}
bool Directory::SetAttributes(DWORD attributes) {
return SetFileAttributesW(path.c_str(), attributes) != 0;
}
bool Directory::Exists(const std::wstring& path) {
DWORD attributes = GetFileAttributesW(path.c_str());
return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY));
}
bool Directory::CreateDirectory(const std::wstring& path) {
return CreateDirectoryW(path.c_str(), nullptr) != 0;
}
bool Directory::Delete(const std::wstring& path) {
return RemoveDirectoryW(path.c_str()) != 0;
}
bool Directory::Move(const std::wstring& source, const std::wstring& destination) {
return MoveFileExW(source.c_str(), destination.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
}
std::vector<std::wstring> Directory::GetFiles(const std::wstring& path) {
std::vector<std::wstring> files;
std::wstring searchPath = path + L"\\*";
WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
return files;
do {
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
files.push_back(findData.cFileName);
} while (FindNextFileW(hFind, &findData) != 0);
FindClose(hFind);
return files;
}
std::vector<std::wstring> Directory::GetDirectories(const std::wstring& path) {
std::vector<std::wstring> directories;
std::wstring searchPath = path + L"\\*";
WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
return directories;
do {
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
std::wstring dirName = findData.cFileName;
if (dirName != L"." && dirName != L"..")
directories.push_back(dirName);
}
} while (FindNextFileW(hFind, &findData) != 0);
FindClose(hFind);
return directories;
}
}

View File

@ -0,0 +1,51 @@
#include "../include/System/IO/DriveInfo.h"
#include <windows.h>
namespace System::IO {
DriveType toDriveType(UINT type) {
switch (type) {
case DRIVE_REMOVABLE: return DriveType::Removable;
case DRIVE_FIXED: return DriveType::Fixed;
case DRIVE_REMOTE: return DriveType::Remote;
case DRIVE_CDROM: return DriveType::CDROM;
case DRIVE_RAMDISK: return DriveType::RAM;
case DRIVE_NO_ROOT_DIR: return DriveType::NoRootDir;
default: return DriveType::Unknown;
}
}
DriveInfo::DriveInfo(const std::wstring& path)
: rootPath(path)
{
Name = rootPath;
UINT type = GetDriveTypeW(rootPath.c_str());
DriveType = toDriveType(type);
IsReady = (type != DRIVE_NO_ROOT_DIR);
WCHAR fsName[MAX_PATH] = {0};
if (GetVolumeInformationW(rootPath.c_str(), nullptr, 0, nullptr, nullptr, nullptr, fsName, MAX_PATH)) {
DriveFormat = fsName;
} else {
DriveFormat.clear();
}
ULARGE_INTEGER total, free, available;
if (GetDiskFreeSpaceExW(rootPath.c_str(), &available, &total, &free)) {
TotalSize = total.QuadPart;
AvailableFreeSpace = available.QuadPart;
} else {
TotalSize = 0;
AvailableFreeSpace = 0;
}
}
std::vector<DriveInfo> DriveInfo::GetDrives() {
std::vector<DriveInfo> drives;
WCHAR buffer[256] = {0};
DWORD len = GetLogicalDriveStringsW(256, buffer);
for (WCHAR* p = buffer; *p; p += wcslen(p) + 1) {
drives.emplace_back(p);
}
return drives;
}
}

View File

@ -0,0 +1,62 @@
#include <windows.h>
#include <stdexcept>
#include "../include/System/IO/File.h"
namespace System::IO {
File::File(const std::wstring& filePath) : path(filePath) { }
std::wstring File::GetPath() const {
return path;
}
DWORD File::GetAttributes(const std::wstring& path) {
return GetFileAttributesW(path.c_str());
}
bool File::SetAttributes(const std::wstring& path, DWORD attributes) {
return SetFileAttributesW(path.c_str(), attributes) != FALSE;
}
bool File::Exists(const std::wstring& path) {
DWORD attributes = GetFileAttributesW(path.c_str());
return (attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY));
}
bool File::Copy(const std::wstring& source, const std::wstring& destination, bool overwrite) {
return CopyFileW(source.c_str(), destination.c_str(), overwrite ? FALSE : TRUE) != 0;
}
bool File::Delete(const std::wstring& path) {
return DeleteFileW(path.c_str()) != 0;
}
bool File::Move(const std::wstring& source, const std::wstring& destination) {
return MoveFileExW(source.c_str(), destination.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
}
uint64_t File::GetSize(const std::wstring& path) {
HANDLE hFile = CreateFileW(
path.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
if (hFile == INVALID_HANDLE_VALUE) {
throw std::runtime_error("Unable to open file to get its size.");
}
LARGE_INTEGER size;
if (!GetFileSizeEx(hFile, &size)) {
CloseHandle(hFile);
throw std::runtime_error("Unable to get file size.");
}
CloseHandle(hFile);
return static_cast<uint64_t>(size.QuadPart);
}
}

View File

@ -0,0 +1,42 @@
#include <windows.h>
#include <stdexcept>
#include "../include/System/IO/FileStream.h"
namespace System::IO {
FileStream::FileStream(const std::wstring& filePath,
DWORD access,
DWORD creationDisposition,
DWORD shareMode,
DWORD flagsAndAttributes)
: path(filePath)
{
hFile = CreateFileW(filePath.c_str(), access, shareMode, nullptr, creationDisposition, flagsAndAttributes, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
throw std::runtime_error("Unable to open file.");
}
FileStream::~FileStream() {
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
}
bool FileStream::Read(void* buffer, DWORD numBytesToRead, DWORD& numBytesRead) {
return ReadFile(hFile, buffer, numBytesToRead, &numBytesRead, nullptr) != 0;
}
bool FileStream::Write(const void* buffer, DWORD numBytesToWrite, DWORD& numBytesWritten) {
return WriteFile(hFile, buffer, numBytesToWrite, &numBytesWritten, nullptr) != 0;
}
bool FileStream::Seek(LARGE_INTEGER offset, DWORD moveMethod, ULARGE_INTEGER& newPos) {
LARGE_INTEGER tempPos = { 0 };
BOOL result = SetFilePointerEx(hFile, offset, &tempPos, moveMethod);
newPos.QuadPart = static_cast<ULONGLONG>(tempPos.QuadPart);
return result != 0;
}
bool FileStream::SetEnd() {
return SetEndOfFile(hFile) != 0;
}
}

View File

@ -0,0 +1,83 @@
using System.Diagnostics;
class Program
{
static void Main()
{
string filesDir = "../files";
string filePath = Path.Combine(filesDir, "bigfile.dat");
string copyPath = Path.Combine(filesDir, "bigfile_copy.dat");
string movedCopyPath = Path.Combine(filesDir, "moved_bigfile_copy.dat");
string movedDirPath = "../files_moved";
int blockSize = 1024 * 1024; // 1 MB
int iterations = 100; // 100 MB
if (!Directory.Exists(filesDir))
Directory.CreateDirectory(filesDir);
byte[] buffer = new byte[blockSize];
for (int i = 0; i < buffer.Length; i++)
buffer[i] = (byte)'A';
var swWrite = Stopwatch.StartNew();
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
for (int i = 0; i < iterations; i++)
fs.Write(buffer, 0, buffer.Length);
}
swWrite.Stop();
Console.WriteLine($"C# Write time: {swWrite.ElapsedMilliseconds} ms");
var swCopy = Stopwatch.StartNew();
File.Copy(filePath, copyPath, true);
swCopy.Stop();
Console.WriteLine($"C# Copy time: {swCopy.ElapsedMilliseconds} ms");
var swRead = Stopwatch.StartNew();
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] readBuffer = new byte[blockSize];
while (fs.Read(readBuffer, 0, readBuffer.Length) > 0) { }
}
swRead.Stop();
Console.WriteLine($"C# Read time: {swRead.ElapsedMilliseconds} ms");
var swAttr = Stopwatch.StartNew();
FileAttributes originalAttrs = File.GetAttributes(filePath);
File.SetAttributes(filePath, originalAttrs | FileAttributes.Hidden);
File.SetAttributes(filePath, originalAttrs);
swAttr.Stop();
Console.WriteLine($"File attribute toggle time: {swAttr.ElapsedMilliseconds} ms");
var swMoveFile = Stopwatch.StartNew();
File.Move(copyPath, movedCopyPath, true);
swMoveFile.Stop();
Console.WriteLine($"Move file time: {swMoveFile.ElapsedMilliseconds} ms");
if (!Directory.Exists(movedDirPath))
Directory.CreateDirectory(movedDirPath);
var swMoveDir = Stopwatch.StartNew();
Directory.Move(filesDir, Path.Combine(movedDirPath, "files"));
swMoveDir.Stop();
Console.WriteLine($"Move directory time: {swMoveDir.ElapsedMilliseconds} ms");
Console.WriteLine("Listing fixed drives:");
var fixedDrives = DriveInfo.GetDrives()
.Where(d => d.IsReady &&
d.DriveType == DriveType.Fixed &&
d.DriveFormat != "squashfs" &&
d.DriveFormat != "tracefs" &&
d.DriveFormat != "pstorefs" &&
d.DriveFormat != "bpf_fs" &&
d.DriveFormat != "rpc_pipefs");
foreach (var drive in fixedDrives)
{
Console.WriteLine($"Drive: {drive.Name} | " +
$"Type: {drive.DriveType} | Format: {drive.DriveFormat} | " +
$"Total: {drive.TotalSize / (1024 * 1024)} MB | " +
$"Free: {drive.AvailableFreeSpace / (1024 * 1024)} MB");
}
}
}

View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cs", "cs\cs.csproj", "{C2B9A492-D5E2-4F2E-6856-CE8104140E99}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C2B9A492-D5E2-4F2E-6856-CE8104140E99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2B9A492-D5E2-4F2E-6856-CE8104140E99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2B9A492-D5E2-4F2E-6856-CE8104140E99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2B9A492-D5E2-4F2E-6856-CE8104140E99}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B1CAAF6F-AAAE-4123-9A24-FC3315E7AFCD}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,136 @@
// #import "@local/nure:0.0.0": *
#import "lib.typ": *
#show: lab-pz-template.with(
doctype: "ЛБ",
title: "Керування зовнішніми пристроями. Нестандартні пристрої",
subject_shorthand: "ОС",
department_gen: "Програмної інженерії",
authors: (
(
name: "Ситник Є. С.",
full_name_gen: "Ситника Єгора Сергійовича",
group: "ПЗПІ-23-2",
gender: "m",
variant: none,
),
(
name: "Малишкін А. С.",
full_name_gen: "Малишкіна Андрія Сергійовича",
group: "ПЗПІ-23-2",
gender: "m",
variant: none,
),
),
mentor: (
name: "Мельнікова Р. В.",
gender: "f",
degree: "доц. каф. ПІ",
),
worknumber: 4,
)
#v(-spacing)
== Мета роботи
Навчитися практичному використанню функцій WinAPI для роботи з файлами.
== Хід роботи
#v(-spacing)
=== Створення класу для роботи з пристроями, файлами та каталогами.
#v(-spacing)
==== Вивчити усі функції, які використовуються для роботи з пристроями, файлами та каталогами в C\#.
В C\# класи для роботи з пристроями, файлами та каталогами знаходяться в просторі імен "System.IO".
Такі класи як "File", "FileStream", "Directory" та "DriveInfo" надають основні засоби для взаємодії з файловою системою.
Клас "File" пропонує статичні методи для виконання базових операцій над файлами.
До них належать: створення нового файлу ("File.Create"), видалення існуючого файлу ("File.Delete"),
перевірка існування файлу ("File.Exists"), копіювання файлу ("File.Copy"), переміщення файлу ("File.Move"), та інші.
Клас "FileStream" надає базову функціональність для роботи з файлами як з потоками даних.
Його основні функції включають відкриття файлу для читання або запису (через конструктори або методи "Open", "OpenRead", "OpenWrite"),
читання даних з файлу ("Read"), запис даних у файл ("Write"), закриття файлового потоку
("Close" або використання блоку "using" для автоматичного закриття), а також керування поточною позицією у файлі ("Seek").
Клас "Directory" надає статичні методи для виконання базових операцій над директоріями.
Серед них: створення нової директорії ("Directory.CreateDirectory"), видалення існуючої директорії ("Directory.Delete"),
перевірка існування директорії ("Directory.Exists"), переміщення директорії ("Directory.Move"),
а також отримання списку файлів у директорії ("Directory.GetFiles") та списку піддиректорій ("Directory.GetDirectories").
Клас "DriveInfo" надає інформацію про логічні диски, підключені до комп'ютера,
для отримання інформації про конкретний диск необхідно створити його екземпляр,
передавши ім'я диску в конструктор, а серед основних властивостей можна знайти ім'я диску ("Name"),
його тип ("DriveType"), стан готовності ("IsReady"), загальний розмір ("TotalSize"),
доступний вільний простір ("AvailableFreeSpace"), формат файлової системи ("DriveFormat"),
мітку тому ("VolumeLabel") та об'єкт кореневого каталогу ("RootDirectory"),
а для отримання інформації про всі диски в системі використовується статичний метод "GetDrives".
==== Визначити клас (класи) для мови С++, інтерфейс для яких подібний інтерфейсу C\#.
Створимо на C++ класи "File", "FileStream", "Directory" та "DriveInfo". Для кожного з них створимо власний файл заголовків.
#figure(image("img/File.h.png", width: 83%), caption: [Вміст файлу "File.h"])
#figure(image("img/FileStream.h.png", width: 83%), caption: [Вміст файлу "FileStream.h"])
#figure(image("img/Directory.h.png", width: 83%), caption: [Вміст файлу "Directory.h"])
#figure(image("img/DriveInfo.h.png", width: 96%), caption: [Вміст файлу "DriveInfo.h"])
==== Реалізувати функції класу (класів) за допомогою функцій WinAPI.
Оскільки WinAPI надає функції, майже ідентичні необхідним, більшість з реалізацій є лише обгортками навколо відповідних функцій WinAPI.
Наприклад функція "SetAttributes" класу "File" має наступний вигляд:
#figure(image("img/File_SetAttributes.png"), caption: [Реалізація функції "SetAttributes" класу "File"])
Таким чином реалізовано більшість методів.
Із методів, що не мають точних аналогів у WinAPI можна виділити такі.
#figure(image("img/File_GetSize.png", width: 85%), caption: [Реалізація функції "GetSize" класу "File"])
#figure(
image("img/Directory_GetDirectories.png", width: 85%),
caption: [Реалізація функції "GetDirectories" класу "Directory"],
)
#figure(image("img/Directory_GetFiles.png"), caption: [Реалізація функції "GetFiles" класу "Directory"])
#figure(image("img/DriveInfo_GetDrives.png"), caption: [Реалізація функції "GetDrives" класу "DriveInfo"])
==== Порівняти швидкодію функцій при їх використанні для C\#, C в разі використання великих файлів.
Створимо прості програми для порівняння швидкодії функцій стандартної бібліотеки C\# та функцій реалізованих на С++.
Для замірів часу на С++ використаємо модуль "chrono" із стандартної бібліотеки.
Для зручності тестів заздалегідь підготуємо всі змінні із потрібними шляхами:
#figure(image("img/cpp_1.png"), caption: [Підготовка до тестів])
Додамо код для тестів:
#figure(image("img/cpp_2.png"), caption: [Тест запису в файл])
#figure(image("img/cpp_3.png"), caption: [Тест копіювання файлу])
#figure(image("img/cpp_4.png"), caption: [Тест читання з файлу])
#figure(image("img/cpp_5.png"), caption: [Тест отримання та встановлення атрибутів файлу])
#figure(image("img/cpp_6.png"), caption: [Тест переміщення файлу])
#figure(image("img/cpp_7.png"), caption: [Тест переміщення директорії])
#figure(image("img/cpp_8.png"), caption: [Тест отримання інформації про носії даних])
Для замірів часу на C\# скористаємося класом "StopWatch" стандартної бібліотеки.
Для зручності тестів заздалегідь підготуємо всі змінні із потрібними шляхами:
#figure(image("img/cs_1.png"), caption: [Підготовка до тестів])
Додамо код для тестів:
#figure(image("img/cs_2.png"), caption: [Тест запису в файл])
#figure(image("img/cs_3.png"), caption: [Тест копіювання файлу])
#figure(image("img/cs_4.png"), caption: [Тест читання з файлу])
#figure(image("img/cs_5.png"), caption: [Тест отримання та встановлення атрибутів файлу])
#figure(image("img/cs_6.png"), caption: [Тест переміщення файлу])
#figure(image("img/cs_7.png"), caption: [Тест переміщення директорії])
#figure(image("img/cs_8.png"), caption: [Тест отримання інформації про носії даних])
Запустимо обидві програми, та порівняємо результати.
// #figure(image("img/cpp_test.png"), caption: [Результат тестування С++ програми])
#figure(image("img/test.jpg", width: 87%), caption: [Результат тестування програм])
Варто зазначити, що оскільки лабораторна робота виконувалась на операційній системі Linux, програми показують дещо різні результати. Для запуску C++ версії було використано шар трансляції Wine, в той час коли C\# версія працює нативно, через це інформація про диски в C++ та C\# версії не співпадають.
Швидкодія обох версій відрізняється незначно, це можна пояснити тим, що обидві програми використовують системну API (WinAPI в випадку із Windows) для взаємодії із файловою системою.
== Висновки
Під час виконання даної лабораторної роботи ми навчилися практичному використанню функцій WinAPI для роботи з файлами.