skyscraper8/skyscraper8/Sophtainer/SplitFileStream.cs
feyris-tan 0c0932e193
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 43s
Added a method to read RF Spectrums off an object storage.
2026-05-03 21:31:47 +02:00

253 lines
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace skyscraper8.SophtainerIO
{
public delegate void FileStreamPartSwitchDelegate(int readSoFar, int currentOffset, int remaining);
internal class SplitFileStream : Stream
{
private string baseFileName;
private uint partSize;
private int currentPart;
private FileStream currentPartStream;
public event FileStreamPartSwitchDelegate PartChangedDuringRead;
public SplitFileStream(string basename, uint partSize = 4294967295)
{
this.baseFileName = basename;
this.partSize = partSize;
this.currentPart = -1;
AcquireCurrentPart();
}
private int CountParts()
{
int result = 0;
while (true)
{
string filename = baseFileName + "." + (66000 + result++);
if (!File.Exists(filename))
{
break;
}
}
return result - 1;
}
private bool AcquireCurrentPart()
{
long requiredPart = Position;
requiredPart /= partSize;
if (currentPartStream != null)
currentPartStream.Position = internalPosition % partSize;
if (requiredPart == currentPart)
return false;
if (currentPartStream != null)
{
currentPartStream.Flush();
currentPartStream.Close();
currentPartStream.Dispose();
}
string filename = baseFileName + "." + (66000 + requiredPart).ToString();
currentPartStream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
currentPartStream.Position = internalPosition % partSize;
int oldPart = currentPart;
currentPart = (int)requiredPart;
return true;
}
public override bool CanRead
{
get
{
AcquireCurrentPart();
return currentPartStream.CanRead;
}
}
public override bool CanSeek
{
get
{
AcquireCurrentPart();
return currentPartStream.CanSeek;
}
}
public override bool CanWrite
{
get
{
AcquireCurrentPart();
return currentPartStream.CanWrite;
}
}
public override long Length
{
get
{
int totalParts = CountParts();
if (totalParts == 1)
{
AcquireCurrentPart();
return currentPartStream.Length;
}
if (totalParts == currentPart)
{
long result = 0;
for (int i = 0; i < totalParts - 1;i++)
{
string filename = baseFileName + (66000 + i);
FileInfo currentFilePart = new FileInfo(filename);
result += currentFilePart.Length;
}
result += currentPartStream.Length;
return result;
}
long result2 = 0;
for (int i = 0; i < totalParts; i++)
{
string filename2 = baseFileName + "." + (66000 + i);
FileInfo currentFilePart = new FileInfo(filename2);
result2 += currentFilePart.Length;
}
return result2;
}
}
private long internalPosition;
public override long Position
{
get
{
return internalPosition;
}
set
{
if (value == 0)
{
if (currentPartStream != null)
{
currentPartStream.Flush();
currentPartStream.Close();
}
currentPartStream = null;
currentPart = -1;
internalPosition = 0;
return;
}
long maxValue = Length;
if (value > Length)
{
throw new ArgumentOutOfRangeException();
}
internalPosition = value;
}
}
public override void Flush()
{
if (currentPartStream != null)
{
currentPartStream.Flush();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
int overallResult = 0;
while (count > 0)
{
if (AcquireCurrentPart())
{
if (overallResult > 0)
{
if (PartChangedDuringRead != null)
{
PartChangedDuringRead(overallResult, offset, count);
}
}
}
long currentPartOffset = currentPartStream.Position;
long currentPartRemaining = partSize - currentPartOffset;
long readAmount = Math.Min(currentPartRemaining, count);
int result = currentPartStream.Read(buffer, offset, (int)readAmount);
if (result == 0)
break;
count -= result;
offset += result;
overallResult += result;
internalPosition += result;
}
return overallResult;
}
public override long Seek(long offset, SeekOrigin origin)
{
switch(origin)
{
case SeekOrigin.Begin:
Position = offset;
break;
case SeekOrigin.Current:
Position += offset;
break;
case SeekOrigin.End:
long maxPos = Length;
Position = maxPos + offset;
break;
default:
throw new NotImplementedException(origin.ToString());
}
return Position;
}
public override void SetLength(long value)
{
long currentLength = Length;
if (value > currentLength)
{
Seek(currentLength, SeekOrigin.Begin);
long neededToWrite = value - currentLength;
byte[] blankBuffer = new byte[4096];
while (neededToWrite > 0)
{
long partSize = Math.Min(blankBuffer.Length, neededToWrite);
Write(blankBuffer, 0, (int)partSize);
neededToWrite -= partSize;
}
}
else
{
throw new NotSupportedException("shrink");
}
}
public override void Write(byte[] buffer, int offset, int count)
{
while (count > 0)
{
AcquireCurrentPart();
long currentPartOffset = currentPartStream.Position;
long currentPartRemaining = partSize - currentPartOffset;
long operationSize = Math.Min(count, currentPartRemaining);
currentPartStream.Write(buffer, offset, (int)operationSize);
offset += (int)operationSize;
count -= (int)operationSize;
internalPosition += operationSize;
}
}
}
}