2016-05-07 2 views
1

Мне нужно прочитать большие файлы csv и вставить их в SQL, моя идея состояла в том, чтобы использовать streamreader и читать файл строки за строкой, потому что если я храню содержимое в переменной, сбой программы. Так вот что я подумал:чтение больших разделенных запятой файлов с помощью streamreader и вставка в sql db в vb.net

using FileStream fs 
Dim list as String 
Try 
Dim MyFile as String = ("C:\\Test.txt") 
      Using fs as FileStream = File.Open(MyFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None) 'file is opened in a protected mode 
       firstline= fs.ReadLine 'treat the firstline as columnname 
       rest = fs.ReadLine 'the rest as rest 
       Do While (Not rest Is Nothing) 'read the complete file 
       list.Add(rest) 

       Filestream.TextFieldType = FileIO.FieldType.Delimited 
       Filestream.SetDelimiters(";") 
       Loop 
      End Using 
     Catch 
      ResultBlock.Text = "File not readable" 
     End Try 

я написал list.Add (остальное), который на самом деле плохая идея, потому что содержание хранится в переменной, то, но мне нужно прочитать и вставить строку для строки в SQL база данных, которая кажется довольно сложной, хотя, у кого есть идея, как я могу справиться с этим?

+0

Вы смешиваете элементы TextFieldParser с FileStream. 'TextFieldType' не является членом FileStream, который не будет компилироваться. FileStream - это тип, поэтому вы не можете ссылаться на него таким образом. Если у вас есть файл для импорта, используйте TextFieldParser или OleDB. – Plutonix

ответ

2

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

Если вы действительно хотите сохранить его управляемым, читатель, писатель и буфер должны быть полностью отделены друг от друга. Это похоже на работу, потому что это больше классов, но на самом деле это проще, потому что каждый класс делает только одно.

Я бы создал класс, который представляет элемент, который вы читаете из файла, со свойствами для каждой записи. Как если бы каждая строка в файле представляет собой человек с именем и номером сотрудника, создать класс как

public class Person 
{ 
    public string FirstName {get;set;} 
    public string LastName {get;set;} 
    public string EmployeeNumber {get;set;} 
} 

Вам нужен буфер. Задача буфера состоит в том, чтобы в него были помещены элементы и при необходимости достигнуть максимального размера. Возможно, вот так:

public interface IBuffer<T> 
{ 
    void AddItem(T item); 
} 

public interface IWriter<T> 
{ 
    void Write(IEnumerable<T> items); 
} 

public class WriterBuffer<T> : IBuffer<T> 
{ 
    private readonly IWriter<T> _writer; 
    private readonly int _maxSize; 
    private readonly List<T> _buffer; 

    public WriterBuffer(IWriter<T> writer, int maxSize) 
    { 
     _writer = writer; 
     _maxSize - maxSize; 
    } 

    public void AddItem(T item) 
    { 
     _buffer.Add(item); 
     if(_buffer.Count >= _maxSize) 
     { 
      _writer.Write(_buffer); 
      _buffer.Clear(); 
     } 
    }  
} 

Тогда ваш класс читателя вообще не знает о писателе. Все, что он знает, это то, что он пишет в буфер.

public class PersonFileReader 
{ 
    private readonly string _filename; 
    private readonly IBuffer<Person> _buffer; 

    public PersonFileReader(string filename, IBuffer<Person> buffer) 
    { 
     _filename = filename; 
     _buffer = buffer; 
    } 

    public void ReadFile() 
    { 
     //Reads from file. 
     //Creates a new Person for each record 
     //Calls _buffer.Add(person) for each Person. 
    }  
} 

public class PersonSqlWriter : IWriter<Person> 
{ 
    private readonly string _connectionString; 

    public PersonSqlWriter(string connectionString) 
    { 
     _connectionString = connectionString; 
    } 

    public void Write(IEnumerable<Person> items) 
    { 
     //Writes the list of items to the database 
     //using _connectionString; 
    } 
} 

В результате каждый из этих классов выполняет только одно. Вы можете использовать их отдельно от других и тестировать их отдельно от других. Это относится к принципу единой ответственности. Ни один класс не слишком сложный, потому что у каждого есть только одна ответственность. Он также применяет принцип инверсии зависимостей. Читатель не знает, что делает буфер. Это просто зависит от интерфейса. Буфер не знает, что делает автор. И писателю все равно, откуда берутся данные.

Теперь сложность заключается в создании объектов. Вам нужно имя файла, строка подключения и максимальный размер буфера. Это означает что-то вроде

var filename = "your file name"; 
var maxBufferSize = 50; 
var connectionString = "your connection string" 

var reader = new PersonFileReader(
    filename, 
    new WriterBuffer<Person>(
     new PersonSqlWriter(connectionString), 
     maxBufferSize)); 

Ваши классы просты, но их все соединять стало немного сложнее. Именно там и происходит инъекция зависимости. Она управляет этим для вас. Я не буду вдаваться в это, потому что это может быть перегрузка информации. Но если вы укажете, что это за приложение: web, WCF-сервис и т. Д., То я мог бы предоставить конкретный пример того, как этот инжекционный контейнер зависимостей, такой как Windsor, Autofac или Unity, может управлять этим для вас.

Это было ново для меня несколько лет назад. Сначала это выглядело скорее как код. Но на самом деле это упрощает создание небольших простых классов, что, в свою очередь, упрощает создание сложных приложений.

Смежные вопросы