많은 양의 데이터가 포함 된 하나의 개체 (중첩 컬렉션 포함)에서 XML 파일을 생성하려고합니다. 그러나 XML에는 제한이있어서 이 50MB을 초과 할 수 없습니다.파일 크기 제한 또는 C#의 제한
이렇게하는 좋은 방법이 있습니까?
업데이트 : 속도는
많은 양의 데이터가 포함 된 하나의 개체 (중첩 컬렉션 포함)에서 XML 파일을 생성하려고합니다. 그러나 XML에는 제한이있어서 이 50MB을 초과 할 수 없습니다.파일 크기 제한 또는 C#의 제한
이렇게하는 좋은 방법이 있습니까?
업데이트 : 속도는
당신이 문자열과 같은 XML 파일을 writting 대신 .NET의 XML 지원을 사용하여 고려 가지고 중요한 것은 각 파일에 대해 50메가바이트으로 분할, 중요하지 않습니다.
저는 도구에서 XML 데이터를 소비 할 수있는 유일한 방법이기 때문에 ~ 10GB의 데이터를 XML에 기록했습니다.
이런 문제가 있었지만 XML이 너무 단순해서 방금 TextWriter를 사용하고 XML을 작성하는 루프를 중첩했습니다.
매력을 발휘하여 XML 객체보다 훨씬 빠릅니다.
모든 것이 xml 개체보다 빠릅니다.) – NotMe
XmlWriter 또는 XDocument으로 큰 xml 파일을 작성할 수 있습니다.
여기 예제. 이 예제는 5 초 이내에 63MB xml 파일을 생성합니다. 이 예제에서는 클래스 XmlWriter을 사용합니다.
using (XmlWriter writer = XmlWriter.Create("YourFilePath"))
{
writer.WriteStartDocument();
writer.WriteStartElement("Root");
for (int i = 0; i < 1000000; i++) //Write one million nodes.
{
writer.WriteStartElement("Root");
writer.WriteAttributeString("value", "Value #" + i.ToString());
writer.WriteString("Inner Text #" + i.ToString());
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
이 방법을 사용하면 여러 기가 바이트의 xml 파일을 작성/읽었지만 정상적으로 작동합니다. 여분의 신용을 위해서 GzipStream을 통해 파일을 압축 할 수 있습니다 ... –
내 작업에서 비슷한 요구 사항을 따르십시오. 내 최선의 노력 (직관적 인, 구현의 용이성, 상대적으로 performant)은 다음과 같습니다. 기본적으로 XmlWriter
으로 작성하여 기본 스트림을 모니터링합니다. 내 파일 크기 제한을 초과하면 현재 XML 조각을 완료하고 파일을 저장하고 스트림을 닫습니다.
두 번째 단계에서 전체 DOM을 메모리에로드하고 반복적으로 노드를 제거하고 허용되는 크기가 될 때까지 문서를 저장합니다. 예를 들어
// arbitrary limit of 10MB
long FileSizeLimit = 10*1024*1024;
// open file stream to monitor file size
using (FileStream file = new FileStream("some.data.xml", FileMode.Create))
using (XmlWriter writer = XmlWriter.Create(file))
{
writer.WriteStartElement("root");
// while not greater than FileSizeLimit
for (; file.Length < FileSizeLimit;)
{
// write contents
writer.WriteElementString(
"data",
string.Format("{0}/{0}/{0}/{0}/{0}", Guid.NewGuid()));
}
// complete fragment; this is the trickiest part,
// since a complex document may have an arbitrarily
// long tail, and cannot be known during file size
// sampling above
writer.WriteEndElement();
writer.Flush();
}
// iteratively reduce document size
// NOTE: XDocument will load full DOM into memory
XDocument document = XDocument.Load("some.data.xml");
XElement root = document.Element("root");
for (; new FileInfo("some.data.xml").Length > FileSizeLimit;)
{
root.LastNode.Remove();
document.Save("some.data.xml");
}
이를 개선 할 수있는 방법이 있습니다; 하나의 가능성은 메모리가 제약 조건이라면 첫 번째 패스에서 실제로 쓰여진 노드의 수를 가져와 하나의 요소가 적은 파일을 다시 쓰고 전체 문서가 원하는 크기가 될 때까지 계속 반복 비트를 다시 쓰는 것입니다.
이 마지막 권장 사항은 특히 다른 파일에 쓰기를 재개하기 위해 작성된 요소를 추적해야하는 경우에 사용할 수있는 경로 일 수 있습니다.
희망이 도움이됩니다.
편집
직관적이며 쉽게 구현, 내가 위에서 언급 한 최적화를 조사하고 가치를 생각하지만. 이것이 내가 가진 것입니다.
쓰기 조상 노드 (즉, 컨테이너 노드 및 마크 업의 모든 다른 종류의) 도움이 연장 방법,
// performs a shallow copy of a given node. courtesy of Mark Fussell
// http://blogs.msdn.com/b/mfussell/archive/2005/02/12/371546.aspx
public static void WriteShallowNode(this XmlWriter writer, XmlReader reader)
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
writer.WriteStartElement(
reader.Prefix,
reader.LocalName,
reader.NamespaceURI);
writer.WriteAttributes(reader, true);
if (reader.IsEmptyElement)
{
writer.WriteEndElement();
}
break;
case XmlNodeType.Text: writer.WriteString(reader.Value); break;
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
writer.WriteWhitespace(reader.Value);
break;
case XmlNodeType.CDATA: writer.WriteCData(reader.Value); break;
case XmlNodeType.EntityReference:
writer.WriteEntityRef(reader.Name);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.DocumentType:
writer.WriteDocType(
reader.Name,
reader.GetAttribute("PUBLIC"),
reader.GetAttribute("SYSTEM"),
reader.Value);
break;
case XmlNodeType.Comment: writer.WriteComment(reader.Value); break;
case XmlNodeType.EndElement: writer.WriteFullEndElement(); break;
}
}
와의 확장 이후, 트리밍 (안 확장 방법을 수행하는 방법 매개 변수 유형은 약간 모호합니다.)
// trims xml file to specified file size. does so by
// counting number of "victim candidates" and then iteratively
// trimming these candidates one at a time until resultant
// file size is just less than desired limit. does not
// consider nested victim candidates.
public static void TrimXmlFile(string filename, long size, string trimNodeName)
{
long fileSize = new FileInfo(filename).Length;
long workNodeCount = 0;
// count number of victim elements in xml
if (fileSize > size)
{
XmlReader countReader = XmlReader.Create(filename);
for (; countReader.Read();)
{
if (countReader.NodeType == XmlNodeType.Element &&
countReader.Name == trimNodeName)
{
workNodeCount++;
countReader.Skip();
}
}
countReader.Close();
}
// if greater than desired file size, and there is at least
// one victim candidate
string workFilename = filename+".work";
for (;
fileSize > size && workNodeCount > 0;
fileSize = new FileInfo(filename).Length)
{
workNodeCount--;
using (FileStream readFile = new FileStream(filename, FileMode.Open))
using (FileStream writeFile = new FileStream(
workFilename,
FileMode.Create))
{
XmlReader reader = XmlReader.Create(readFile);
XmlWriter writer = XmlWriter.Create(writeFile);
long j = 0;
bool hasAlreadyRead = false;
for (; (hasAlreadyRead) || reader.Read();)
{
// if node is a victim node
if (reader.NodeType == XmlNodeType.Element &&
reader.Name == trimNodeName)
{
// if we have not surpassed this iteration's
// allowance, preserve node
if (j < workNodeCount)
{
writer.WriteNode(reader, true);
}
j++;
// if we have exceeded this iteration's
// allowance, trim node (and whitespace)
if (j >= workNodeCount)
{
reader.ReadToNextSibling(trimNodeName);
}
hasAlreadyRead = true;
}
else
{
// some other xml content we should preserve
writer.WriteShallowNode(reader);
hasAlreadyRead = false;
}
}
writer.Flush();
}
File.Copy(workFilename, filename, true);
}
File.Delete(workFilename);
}
Xml에 공백이 포함되어 있으면 마지막으로 남아있는 희생 노드와 닫기 컨테이너 요소 태그 사이의 공백이 손실됩니다. skip 절을 변경하여 (j++
문을 건너 뛰고) 공백을 추가로 줄일 수 있습니다. 위에 제시된 솔루션은 소스 파일의 최소 파일 크기 복제본을 생성합니다.
나머지는 무엇을 할 것입니까? 출력 파일은 어떻게 생겼을까요? –
50MB 파일로 분할하는 것과 관련하여 문제가있는 것은 무엇입니까? –