在 C# 中达到一定大小时创建 csv 文件
Create csv file when certain size reached in c#
我有一种从列表内容写入 csv 的方法。如果 csv 文件大小达到特定大小,如 5MB,我想创建一个新的 csv 文件,这样如果列表内容很大,它就不会变得太大。下面是我的代码,但它不起作用。我收到错误 "file is being used by another process"。看起来这不是创建新 csv 文件的正确方法。
public static void WriteCSV<T>(IEnumerable<T> items, string path)
{
Type itemType = typeof(T);
var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.OrderBy(p => p.Name);
int filenumber = 0;
using (var writer = new StreamWriter(path))
{
writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));
foreach (var item in items)
{
writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
if (writer.BaseStream.Length > 5120)
{
writer.Close();
writer.Dispose();
filenumber++;
var writer2 = new StreamWriter(string.Format(path, filenumber), false);
}
}
}
}
你的问题有两个方面。
- 方法
string.Format(path, filenumber)
没有达到您的预期。它实际上需要一个格式字符串作为第一个参数,如 "value goes here {0}"
和一个变量来代替 {0}
。因为你只给它一个路径,它会 return 只是路径,它与你以前的文件同名。因此你得到了错误,因为你试图再次访问同一个文件。
1 的解决方案):
1.1) 你需要把路径分成路径和文件名,
1.2) 然后取不带扩展名的文件名,
1.3) 然后将数字连接到文件名
1.4)重构路径
问题 2)
对集合的迭代不应在作者的 using 块内。它甚至不取决于作者。这使得您不可能在每次不指定新实例的情况下使用另一个编写器。这会使代码变得丑陋和不必要的复杂。
删除 using 块并像您已经做的那样手动处理 writer:
这是一个可以解决问题的示例程序。
void Main()
{
string path = @"C:\WorkSpace\temp\test\fileName.csv";
List<string> items = Enumerable.Range(1, 1200).Select(x => $"Something: {x} else {x+2} ").ToList();
int filenumber = 0;
var writer = new StreamWriter(path);
string pathOnly = Path.GetDirectoryName(path);
string fileName = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path);
foreach (var item in items)
{
writer.WriteLine(string.Join(", ", item.Split(' ')));
if (writer.BaseStream.Length > 120)
{
writer.Close();
writer.Dispose();
filenumber++;
writer = new StreamWriter(Path.Combine(pathOnly, $"{fileName}{filenumber}{extension}"), false);
}
}
// don't forget to close and dispose the last instance of the writer
writer.Close();
writer.Dispose();
}
我有一种从列表内容写入 csv 的方法。如果 csv 文件大小达到特定大小,如 5MB,我想创建一个新的 csv 文件,这样如果列表内容很大,它就不会变得太大。下面是我的代码,但它不起作用。我收到错误 "file is being used by another process"。看起来这不是创建新 csv 文件的正确方法。
public static void WriteCSV<T>(IEnumerable<T> items, string path)
{
Type itemType = typeof(T);
var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.OrderBy(p => p.Name);
int filenumber = 0;
using (var writer = new StreamWriter(path))
{
writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));
foreach (var item in items)
{
writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
if (writer.BaseStream.Length > 5120)
{
writer.Close();
writer.Dispose();
filenumber++;
var writer2 = new StreamWriter(string.Format(path, filenumber), false);
}
}
}
}
你的问题有两个方面。
- 方法
string.Format(path, filenumber)
没有达到您的预期。它实际上需要一个格式字符串作为第一个参数,如"value goes here {0}"
和一个变量来代替{0}
。因为你只给它一个路径,它会 return 只是路径,它与你以前的文件同名。因此你得到了错误,因为你试图再次访问同一个文件。
1 的解决方案):
1.1) 你需要把路径分成路径和文件名,
1.2) 然后取不带扩展名的文件名,
1.3) 然后将数字连接到文件名
1.4)重构路径
问题 2)
对集合的迭代不应在作者的 using 块内。它甚至不取决于作者。这使得您不可能在每次不指定新实例的情况下使用另一个编写器。这会使代码变得丑陋和不必要的复杂。
删除 using 块并像您已经做的那样手动处理 writer: 这是一个可以解决问题的示例程序。
void Main()
{
string path = @"C:\WorkSpace\temp\test\fileName.csv";
List<string> items = Enumerable.Range(1, 1200).Select(x => $"Something: {x} else {x+2} ").ToList();
int filenumber = 0;
var writer = new StreamWriter(path);
string pathOnly = Path.GetDirectoryName(path);
string fileName = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path);
foreach (var item in items)
{
writer.WriteLine(string.Join(", ", item.Split(' ')));
if (writer.BaseStream.Length > 120)
{
writer.Close();
writer.Dispose();
filenumber++;
writer = new StreamWriter(Path.Combine(pathOnly, $"{fileName}{filenumber}{extension}"), false);
}
}
// don't forget to close and dispose the last instance of the writer
writer.Close();
writer.Dispose();
}