Страницы

Поиск по вопросам

пятница, 27 декабря 2019 г.

Примонтировать архив как диск

#windows #архивация #диск #монтирование #поиск_программ


Хочу примонтировать архив (желательно 7z, но можно другой хороший) как виртуальный
диск в Windows. При этом должны выполняться следующие условия:


Считаем, что есть пустой архив. Когда именно он создастся - не важно.
Этот архив монтируется как виртуальный диск.
На этот диск будет записан ровно один файл.
Сжатие должно происходить непосредственно при записи.
Запись будет последовательной (но НЕ realtime).
Ожидаемый объём записываемого от 100 ГБ до 500 ГБ.
Ожидаемый объём архива в 500 раз меньше объёма записываемого файла.
На дисках не достаточно свободного места, чтобы вместить несжатый файл.
Желательно, чтобы последовательное считывание после записи тоже было возможно.


Записываться будет несжатое avi, причём обязательно под Windows.

С помощью каких программ такое можно осуществить?

Замечу, что 7zip умеет делать потоковую архивацию. Например, следующей командой можно
упаковать выводимый текст в архив cmd.7z под именем (файла) help.txt (ключ -si):

cmd /? | "C:\Program Files (x86)\7-Zip\7z.exe" a -sihelp.txt cmd.7z


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

PS: Этот вопрос на английском.
    


Ответы

Ответ 1



Можно попробовать использовать WebDAV. Windows умеет монтировать WebDAV-папки как сетевые диски. Начать можно с вот такого сервера (код на C#), который эмулирует пустой диск, ожидая пока ему не передадут файл: using System; using System.Globalization; using System.IO; using System.Net; using System.Xml.Linq; namespace HttpPipe { static class Program { static readonly Uri ListenUri = new Uri("http://localhost/share/"); static void Main(string[] args) { CultureInfo.DefaultThreadCurrentCulture = CultureInfo.GetCultureInfo("en-US"); var listener = new HttpListener { Prefixes = { $"{ListenUri.Scheme}://*:{ListenUri.Port}{ListenUri.PathAndQuery}" }, }; listener.Start(); bool processing = false; try { while (true) { processing = false; var ctx = listener.GetContext(); processing = true; try { var uri = ctx.Request.Url; Console.Error.WriteLine($"{ctx.Request.HttpMethod} {uri} {ctx.Request.ContentType} {ctx.Request.ContentLength64}"); var root = new Uri(uri, ListenUri.PathAndQuery); if (uri + "/" == root.ToString()) uri = root; uri = uri.MakeRelativeUri(root); if (uri.IsAbsoluteUri || uri.ToString().StartsWith("..")) throw new Exception("Неправильный URI: " + uri); if (ProcessContext(ctx, uri.ToString())) break; } finally { ctx.Response.Close(); } } } catch (Exception ex) when (processing) { Console.Error.WriteLine("ERROR: " + ex); } catch (Exception) { } listener.Stop(); } static readonly XNamespace DAV = "DAV:"; private static bool ProcessContext(HttpListenerContext ctx, string uri) { ctx.Response.SendChunked = false; switch (ctx.Request.HttpMethod) { case "OPTIONS": ctx.Response.SetStatus(HttpStatusCode.OK); ctx.Response.AddHeader("DAV", "1"); break; case "PROPFIND": if (uri != "") { ctx.Response.SetStatus(HttpStatusCode.NotFound); } else { var prop = new XElement(DAV + "prop"); prop.SetElementValue(DAV + "creationdate", DateTime.UtcNow.ToString("s") + "Z"); prop.SetElementValue(DAV + "getlastmodified", DateTime.UtcNow.ToString("R")); prop.SetElementValue(DAV + "displayname", "share"); prop.Add(new XElement(DAV + "resourcetype", new XElement(DAV + "collection"))); var response = new XElement(DAV + "response"); response.SetElementValue(DAV + "href", ListenUri.PathAndQuery); response.Add(new XElement(DAV + "propstat", new XElement(DAV + "status", "HTTP/1.1 200 OK"), prop)); ctx.Response.StatusCode = 207; ctx.Response.StatusDescription = "Multi Status"; ctx.Response.Send(new XElement(DAV + "multistatus", new XAttribute(XNamespace.Xmlns + "d", DAV), response)); } break; case "PUT": if (ctx.Request.ContentLength64 > 0) { foreach (string header in ctx.Request.Headers) { Console.Error.WriteLine($" {header}: {ctx.Request.Headers[header]}"); } using (var output = Console.OpenStandardOutput()) { ctx.Request.InputStream.CopyTo(output); } ctx.Response.SetStatus(HttpStatusCode.NoContent); return true; } ctx.Response.SetStatus(HttpStatusCode.NoContent); return false; default: ctx.Response.SetStatus(HttpStatusCode.NotImplemented); break; } return false; } static void SetStatus(this HttpListenerResponse resp, HttpStatusCode status) { resp.StatusCode = (int)status; resp.StatusDescription = status.ToString(); } static void Send(this HttpListenerResponse resp, XElement content) { var ms = new MemoryStream(); content.Save(ms); ms.Position = 0; resp.ContentType = "application/xml; charset=utf-8"; resp.ContentLength64 = ms.Length; ms.CopyTo(resp.OutputStream); } } } Когда приходит файл - он выводит его содержимое в стандартный вывод и завершает работу. Полезные ссылки: RFC 4918 - HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV) WebDAV-API Яндекс-Диска - тут есть ценные примеры

Комментариев нет:

Отправить комментарий