过去几天我一直在努力解决这个问题,但我似乎无法让它发挥作用。
所以我有一个这样格式的txt文件:
id;könyvcím;szerző;kiadó;kiadási év;
我正在使用结构和列表,例如:
public static List<Books> BooksList = new List<Books>();
public struct Books
{
public int id;
public string title;
public string writer;
public string publisher;
public int published_year;
}
而且我还将所有这些都放入一个基于如下结构的列表中:
StreamReader booksRead = new StreamReader("konyvek.txt", Encoding.UTF8);
booksRead.ReadLine();
while (!booksRead.EndOfStream)
{
string[] split = booksRead.ReadLine().Split(';');
Books inRead = new Books();
inRead.id = Convert.ToInt32(split[0]);
inRead.title = split[1];
inRead.writer = split[2];
inRead.publisher = split[3];
inRead.published_year = Convert.ToInt32(split[4]);
BooksList.Add(inRead);
}
booksRead.Close();
例如,我只想找到 ID 为 2 的行的位置,然后从我的文本文件中删除该行。我试图获取我想要的行的索引,并像这样从我的文本文件中删除它,但它甚至无法获取索引,我尝试使用 IndexOf、FindIndex 并尝试进行循环。我很确定我的结构对我这样使用它不满意,因为我在运行代码时遇到这样的错误:
<块引用>System.InvalidCastException: '无法将 'Books' 类型的对象转换为 输入“System.IConvertible”。
这是我尝试获取要删除的行的索引的方法
Books item = new Books();
for (int i = 0; i < BooksList.Count; i++)
{
if (Convert.ToInt32(textBox_id_delete.Text) == item.id)
{
RemoveAt = item.id;
}
}
int index = BooksList.FindIndex(x => Convert.ToInt32(x) == RemoveAt);
MessageBox.Show(Convert.ToString(index));
我很确定我的做法非常错误,我愿意接受任何帮助。
答案 0 :(得分:1)
出于多种原因,您完全错了。
首先,你会怎么做:
void Main()
{
var filename = @"c:\myFolder\mybooklist.txt";
// read into an enumerable
var books = File.ReadAllLines(filename)
.Select(x => x.Split(';'))
.Select(x => new Book {
Id = int.TryParse(x[0], out int bookId)?bookId:0,
Title = x[1],
Writer = x[2],
Publisher = x[3],
Published_year=int.TryParse(x[4], out int year)?year:0
});
// remove the one with id 2
// and save back
var otherBooks = books.Where(b => b.Id != 2);
File.WriteAllLines(filename, otherBooks.Select(b => $"{b.Id};{b.Title};{b.Writer};{b.Publisher};{b.Published_year}"));
}
public struct Book
{
public int Id;
public string Title;
public string Writer;
public string Publisher;
public int Published_year;
}
现在这有什么问题。
恕我直言,您应该简单地使用一个数据库,一个嵌入式数据库,例如 LiteDb 或 Sqlite。如果您想查看 LiteDb 或 Sqlite 示例,请告诉我。
编辑:我正在添加 SQLite 和 LiteDb 示例。无论哪种情况,您都需要分别从 Nuget 添加 Sqlite.Data.Sqlite 和 LiteDB 并添加 using 语句。
如果是 SQLite,请注意您可以使用 Linq 添加一些驱动程序。我直接使用了 ADO.Net 命令,没有使用 Book 类进行映射。
LiteDB 是一个用 C# 为 C# 编写的 NoSQL 数据库,可以直接使用对象并支持 Linq 开箱即用。
样品仅显示两者的表面。
答案 1 :(得分:1)
SQLite 示例:
private static readonly string dataFile = @"d:\temp\books.s3db";
void Main()
{
CreateDb(dataFile);
SeedSampleData(dataFile);
// List the current data
Console.WriteLine("Current Data");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
DeleteSampleRow(dataFile);
// List the current data
Console.WriteLine("After deleting");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
}
void DeleteSampleRow(string dbName)
{
string deleteById = "delete from books where id = @id";
string deleteByTitle = "delete from books where Title = @title";
string deleteByWriter = "delete from books where Writer = @writer";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmdById = new SQLiteCommand(deleteById, cn))
using (SQLiteCommand cmdByTitle = new SQLiteCommand(deleteByTitle, cn))
using (SQLiteCommand cmdByWriter = new SQLiteCommand(deleteByWriter, cn))
{
cmdById.Parameters.Add("@id", DbType.Int32).Value = 2; // delete the book with id = 2
cmdByTitle.Parameters.Add("@title", DbType.String).Value = $"Sample Title #5"; // delete all books having title "Sample Title #5"
cmdByWriter.Parameters.Add("@writer", DbType.String).Value = $"Sample Writer #3"; // delete all books written by "Sample Writer #3"
cn.Open();
cmdById.ExecuteNonQuery();
cmdByTitle.ExecuteNonQuery();
cmdByWriter.ExecuteNonQuery();
cn.Close();
}
}
void ListData(string dbName)
{
string selectCommand = "select * from books";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmd = new SQLiteCommand(selectCommand, cn))
{
cn.Open();
var r = cmd.ExecuteReader();
while (r.Read())
{
Console.WriteLine($"{r["id"]},{r["title"]},{r["writer"]},{r["publisher"]},{r["published_year"]}");
}
cn.Close();
}
}
private void CreateDb(string dbName)
{
if (File.Exists(dbName)) // if it exists, delete and create afresh, just for sampling
{
File.Delete(dbName);
}
string createTable = @"Create Table books (
id int primary key not null,
title varchar(500) not null,
writer varchar(100) not null,
publisher varchar(100) not null,
published_year int not null
)";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmd = new SQLiteCommand(createTable, cn))
{
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
}
private void SeedSampleData(string dbName)
{
string insertCommand = @"insert into books
(id, title, writer, publisher, published_year)
values
(@id, @title, @writer, @publisher, @year);";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmd = new SQLiteCommand(insertCommand, cn))
{
cmd.Parameters.Add("@id", DbType.Int32);
cmd.Parameters.Add("@title", DbType.String);
cmd.Parameters.Add("@writer", DbType.String);
cmd.Parameters.Add("@publisher", DbType.String);
cmd.Parameters.Add("@year", DbType.Int32);
Random r = new Random();
cn.Open();
int id = 1;
using (SQLiteTransaction transaction = cn.BeginTransaction())
{
cmd.Parameters["@id"].Value = id++;
cmd.Parameters["@title"].Value = $"Around the World in Eighty Days";
cmd.Parameters["@writer"].Value = $"Jules Verne";
cmd.Parameters["@publisher"].Value = $"Le Temps, Pierre-Jules Hetzel";
cmd.Parameters["@year"].Value = 1873;
cmd.ExecuteNonQuery();
cmd.Parameters["@id"].Value = id++;
cmd.Parameters["@title"].Value = $"A Tale of Two Cities";
cmd.Parameters["@writer"].Value = $"Charles Dickens";
cmd.Parameters["@publisher"].Value = $"Chapman & Hall";
cmd.Parameters["@year"].Value = 1859;
cmd.ExecuteNonQuery();
// add dummy 10 more rows
for (int i = 0; i < 10; i++)
{
cmd.Parameters["@id"].Value = id++;
cmd.Parameters["@title"].Value = $"Sample Title #{i}";
cmd.Parameters["@writer"].Value = $"Sample Writer #{r.Next(1, 5)}";
cmd.Parameters["@publisher"].Value = $"Sample Publisher #{i}";
cmd.Parameters["@year"].Value = r.Next(1980, 2022);
cmd.ExecuteNonQuery();
}
transaction.Commit();
}
// databases generally use some indexes
new SQLiteCommand(@"Create Index if not exists ixId on books (id);", cn).ExecuteNonQuery();
new SQLiteCommand(@"Create Index if not exists ixTitle on books (title);", cn).ExecuteNonQuery();
new SQLiteCommand(@"Create Index if not exists ixWriter on books (writer);", cn).ExecuteNonQuery();
new SQLiteCommand(@"Create Index if not exists ixPublisher on books (publisher);", cn).ExecuteNonQuery();
cn.Close();
}
}
答案 2 :(得分:0)
当您将图书从文件放入列表时,您可以搜索该图书以从 BooksList
中删除。
删除它并将 BooksList
保存到文件中。
var removeBook = BookList.FirstOrDefault(book => book.id == removeId);
if (removeBook != null)
{
BookList.Remove(removeBook);
}
var booksAsString = BookList.Select(book => $"{book.id};{book.title};{book.writer};{book.publisher};{book.published_year}");
File.WriteAllLines("konyvek.txt", booksAsString, Encoding.UTF8);
答案 3 :(得分:0)
LiteDb sample:
private static readonly string dataFile = @"d:\temp\books.litedb";
void Main()
{
//CreateDb(dataFile); // this step is not needed with LiteDB
// instead we just simply delete the datafile if it exists
// for starting afresh
// if it exists, delete and create afresh, just for sampling
// so you can run this same sample over and over if you wish
if (File.Exists(dataFile))
{
File.Delete(dataFile);
}
SeedSampleData(dataFile);
// List the current data
Console.WriteLine("Current Data");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
DeleteSampleRow(dataFile);
// List the current data
Console.WriteLine("After deleting");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
}
void DeleteSampleRow(string dbName)
{
using (var db = new LiteDatabase(dbName))
{
var bookCollection = db.GetCollection<Book>("Books");
// by ID
bookCollection.Delete(2);
// by Title
bookCollection.DeleteMany(c => c.Title == "Sample Title #5");
// by Writer
bookCollection.DeleteMany(c => c.Writer == "Sample Writer #3");
}
}
void ListData(string dbName)
{
using (var db = new LiteDatabase(dbName))
{
var bookCollection = db.GetCollection<Book>("Books");
foreach (var book in bookCollection.FindAll())
{
Console.WriteLine($"{book.Id},{book.Title},{book.Writer},{book.Publisher},{book.Published_year}");
}
}
}
private void SeedSampleData(string dbName)
{
Random r = new Random();
var books = new List<Book> {
new Book {Title="Around the World in Eighty Days",Writer = "Jules Verne",Publisher = "Le Temps, Pierre-Jules Hetzel",Published_year= 1873},
new Book {Title="A Tale of Two Cities",Writer = "Charles Dickens",Publisher = "Chapman & Hall",Published_year= 1859},
};
// add dummy 10 more rows
books.AddRange(Enumerable.Range(0, 10).Select(i => new Book
{
Title = $"Sample Title #{i}",
Writer = $"Sample Writer #{r.Next(1, 5)}",
Publisher = $"Sample Publisher #{i}",
Published_year = r.Next(1980, 2022)
}));
using (var db = new LiteDatabase(dbName))
{
var bookCollection = db.GetCollection<Book>("Books");
bookCollection.InsertBulk(books);
// databases generally use some indexes
// create the same indexes that we created in SQLite sample
bookCollection.EnsureIndex(c => c.Id);
bookCollection.EnsureIndex(c => c.Title);
bookCollection.EnsureIndex(c => c.Writer);
bookCollection.EnsureIndex(c => c.Publisher);
}
}
public class Book
{
public int Id {get;set;}
public string Title {get;set;}
public string Writer {get;set;}
public string Publisher {get;set;}
public int Published_year {get;set;}
}
答案 4 :(得分:0)
欢迎来到 SO。我将假设您有理由将数据保存在文本文件中。正如几个答案所建议的那样,如果您需要在文本文件中使用它,最简单的方法就是使用您想要的行创建一个新文件。
一种方法是使用 interator 函数来过滤行。这使您可以轻松地使用 .NET File 类来完成其余的工作 - 创建新文件并根据需要删除旧文件。通常保留旧文件并将其存档也很有用,但无论如何,这里有一种过滤行的方法。
static void Main(string[] _)
{
var filteredLines = FilterOnID(File.ReadAllLines("datafile.txt"), "2");
File.WriteAllLines("updated.datafile.txt", filteredLines);
// rename if necessary
File.Delete("datafile.txt");
File.Move("updated.datafile.txt", "datafile.txt");
}
static IEnumerable<string> FilterOnID(IEnumerable<string> lines, string id)
{
foreach (var line in lines)
{
var fields = line.Split(';');
if (fields.Length != 0 || !string.IsNullOrEmpty(fields[0]))
{
if (id == fields[0])
continue;
}
yield return line;
}
}
为了测试,我添加了这样的简单文件:
1;field1;field2;field3
2;field1;field2;field3
3;field1;field2;field3
4;field1;field2;field3
5;field1;field2;field3
6;field1;field2;field3
运行后你会得到这个:
1;field1;field2;field3
3;field1;field2;field3
4;field1;field2;field3
5;field1;field2;field3
6;field1;field2;field3