2012-01-29 34 views
6

Tôi có kết nối sql từ xa trong C# cần thực hiện truy vấn và lưu kết quả của nó vào đĩa cứng cục bộ của người dùng. Có một lượng lớn dữ liệu mà điều này có thể trả về, vì vậy cần phải nghĩ đến cách lưu trữ hiệu quả. Tôi đã đọc trước đó trước tiên đưa toàn bộ kết quả vào bộ nhớ và sau đó viết nó không phải là một ý tưởng tốt, vì vậy nếu ai đó có thể giúp đỡ, sẽ là tuyệt vời!Cách ghi hiệu quả vào tệp từ bộ dữ liệu SQL trong C#?

Tôi hiện đang lưu trữ các dữ liệu kết quả sql vào một DataTable, mặc dù tôi đang nghĩ nó có thể là tốt hơn làm một cái gì đó trong while(myReader.Read(){...} Dưới đây là đoạn code mà nhận được kết quả:

  DataTable t = new DataTable(); 
      string myQuery = QueryLoader.ReadQueryFromFileWithBdateEdate(@"Resources\qrs\qryssysblo.q", newdate, newdate); 
      using (SqlDataAdapter a = new SqlDataAdapter(myQuery, sqlconn.myConnection)) 
      { 
       a.Fill(t); 
      } 

      var result = string.Empty; 
    for(int i = 0; i < t.Rows.Count; i++) 
    { 
     for (int j = 0; j < t.Columns.Count; j++) 
     { 
      result += t.Rows[i][j] + ","; 
     } 


     result += "\r\n"; 
    } 

Vì vậy, bây giờ tôi có điều này chuỗi kết quả rất lớn. Và tôi có dữ liệu. Phải có một cách tốt hơn để làm điều đó?

Cảm ơn.

+0

Bản sao có thể có của http://stackoverflow.com/questions/2244655/how-to-serialize-a-datatable-to-a-string –

+0

Bạn chỉ cần viết cho một tệp phẳng chưa được định dạng hoặc sẽ tốt hơn để đưa dữ liệu vào các cột như bảng tính .csv? – DOK

+0

tệp dấu phẩy phẳng. – Sam

Trả lời

18

Bạn đang đi đúng hướng. Sử dụng vòng lặp với while(myReader.Read(){...} và ghi từng bản ghi vào tệp văn bản bên trong vòng lặp. Khuôn khổ .NET và hệ điều hành sẽ chăm sóc xả bộ đệm vào đĩa theo cách hiệu quả.

using(SqlConnection conn = new SqlConnection(connectionString)) 
using(SqlCommand cmd = conn.CreateCommand()) 
{ 
    conn.Open(); 
    cmd.CommandText = QueryLoader.ReadQueryFromFileWithBdateEdate(
    @"Resources\qrs\qryssysblo.q", newdate, newdate); 

    using(SqlDataReader reader = cmd.ExecuteReader()) 
    using(StreamWriter writer = new StreamWriter("c:\temp\file.txt")) 
    { 
    while(reader.Read()) 
    { 
     // Using Name and Phone as example columns. 
     writer.WriteLine("Name: {0}, Phone : {1}", 
     reader["Name"], reader["Phone"]); 
    } 
    } 
} 
+0

Cảm ơn. tôi nên sử dụng phương pháp viết nào? streamwriter? IO? một ví dụ sẽ rất hữu ích. cảm ơn – Sam

+0

Sử dụng StreamWriter nếu bạn muốn ghi vào một tệp. Xem bản cập nhật của tôi với một ví dụ. –

+0

Cảm ơn. Đối với tất cả các hàng tôi đang sử dụng: 'StringBuilder row = new StringBuilder(); cho (int i = 0; i Sam

2

Tôi đồng ý rằng đặt cược tốt nhất của bạn ở đây sẽ là sử dụng SqlDataReader. Một cái gì đó như thế này:

StreamWriter YourWriter = new StreamWriter(@"c:\testfile.txt"); 
SqlCommand YourCommand = new SqlCommand(); 
SqlConnection YourConnection = new SqlConnection(YourConnectionString); 
YourCommand.Connection = YourConnection; 
YourCommand.CommandText = myQuery; 

YourConnection.Open(); 

using (YourConnection) 
{ 
    using (SqlDataReader sdr = YourCommand.ExecuteReader()) 
     using (YourWriter) 
     { 
      while (sdr.Read()) 
       YourWriter.WriteLine(sdr[0].ToString() + sdr[1].ToString() + ","); 

     } 
} 

Tâm trí bạn, trong while vòng lặp, bạn có thể viết rằng dòng vào tập tin văn bản trong bất kỳ định dạng mà bạn thấy phù hợp với dữ liệu cột từ SqlDataReader.

1

tôi đã đưa ra với điều này, đó là một nhà văn tốt CSV so với câu trả lời khác:

public static class DataReaderExtension 
{ 
    public static void ToCsv(this IDataReader dataReader, string fileName, bool includeHeaderAsFirstRow) 
    { 

     const string Separator = ","; 

     StreamWriter streamWriter = new StreamWriter(fileName); 

     StringBuilder sb = null; 

     if (includeHeaderAsFirstRow) 
     { 
      sb = new StringBuilder(); 
      for (int index = 0; index < dataReader.FieldCount; index++) 
      { 
       if (dataReader.GetName(index) != null) 
        sb.Append(dataReader.GetName(index)); 

       if (index < dataReader.FieldCount - 1) 
        sb.Append(Separator); 
      } 
      streamWriter.WriteLine(sb.ToString()); 
     } 

     while (dataReader.Read()) 
     { 
      sb = new StringBuilder(); 
      for (int index = 0; index < dataReader.FieldCount; index++) 
      { 
       if (!dataReader.IsDBNull(index)) 
       { 
        string value = dataReader.GetValue(index).ToString(); 
        if (dataReader.GetFieldType(index) == typeof(String)) 
        { 
         if (value.IndexOf("\"") >= 0) 
          value = value.Replace("\"", "\"\""); 

         if (value.IndexOf(Separator) >= 0) 
          value = "\"" + value + "\""; 
        } 
        sb.Append(value); 
       } 

       if (index < dataReader.FieldCount - 1) 
        sb.Append(Separator); 
      } 

      if (!dataReader.IsDBNull(dataReader.FieldCount - 1)) 
       sb.Append(dataReader.GetValue(dataReader.FieldCount - 1).ToString().Replace(Separator, " ")); 

      streamWriter.WriteLine(sb.ToString()); 
     } 
     dataReader.Close(); 
     streamWriter.Close(); 
    } 
} 

sử dụng: mydataReader.ToCsv ("myfile.csv", true)

+1

Bạn không muốn '- 1' trên' for (int index = 0; index vapcguy

+1

@vacguy nhờ tôi đã sửa câu trả lời của mình –

2

Rob Sedgwick Câu trả lời là hơn thích nó, nhưng có thể được cải thiện và đơn giản hóa. Đây là cách tôi đã làm nó:

string separator = ";"; 
string fieldDelimiter = ""; 
bool useHeaders = true; 

string connectionString = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; 

using (SqlConnection conn = new SqlConnection(connectionString)) 
{ 
    using (SqlCommand cmd = conn.CreateCommand()) 
    { 
      conn.Open(); 
      string query = @"SELECT whatever"; 

      cmd.CommandText = query; 

      using (SqlDataReader reader = cmd.ExecuteReader()) 
      { 
       if (!reader.Read()) 
       { 
        return; 
       } 

       List<string> columnNames = GetColumnNames(reader); 

       // Write headers if required 
       if (useHeaders) 
       { 
        first = true; 
        foreach (string columnName in columnNames) 
        { 
          response.Write(first ? string.Empty : separator); 
          line = string.Format("{0}{1}{2}", fieldDelimiter, columnName, fieldDelimiter); 
          response.Write(line); 
          first = false; 
        } 

        response.Write("\n"); 
       } 

       // Write all records 
       do 
       { 
        first = true; 
        foreach (string columnName in columnNames) 
        { 
          response.Write(first ? string.Empty : separator); 
          string value = reader[columnName] == null ? string.Empty : reader[columnName].ToString(); 
          line = string.Format("{0}{1}{2}", fieldDelimiter, value, fieldDelimiter); 
          response.Write(line); 
          first = false; 
        } 

        response.Write("\n"); 
       } 
       while (reader.Read()); 
      } 
    } 
} 

Và bạn cần phải có một hàm GetColumnNames:

List<string> GetColumnNames(IDataReader reader) 
{ 
    List<string> columnNames = new List<string>(); 
    for (int i = 0; i < reader.FieldCount; i++) 
    { 
     columnNames.Add(reader.GetName(i)); 
    } 

    return columnNames; 
} 
1

Sử dụng các đối tượng phản ứng mà không có một response.Close() nguyên nhân ít nhất là trong một số trường hợp html của việc viết trang ra dữ liệu được ghi vào tệp. Nếu bạn sử dụng Response.Close(), kết nối có thể bị đóng sớm và gây ra lỗi khi tạo tệp.

Bạn nên sử dụng HttpApplication.CompleteRequest() tuy nhiên điều này dường như luôn khiến html được ghi vào cuối tệp.

Tôi đã thử luồng kết hợp với đối tượng phản hồi và đã thành công trong môi trường phát triển. Tôi chưa thử nó trong sản xuất.

2

Giữ cách tiếp cận ban đầu của bạn, đây là một chiến thắng nhanh chóng:

Thay vì sử dụng String như một bộ đệm tạm thời, sử dụng StringBuilder. Điều đó sẽ cho phép bạn sử dụng hàm .append(String) cho các kết nối, thay vì sử dụng toán tử +=.

Nhà điều hành += đặc biệt không hiệu quả, vì vậy nếu bạn đặt nó trên một vòng lặp và được lặp lại (có thể) hàng triệu lần, hiệu suất sẽ bị ảnh hưởng.

Phương pháp .append(String) sẽ không tiêu diệt các đối tượng ban đầu, do đó, nó nhanh hơn

1

tôi đã sử dụng CSV để xuất dữ liệu từ cơ sở dữ liệu bởi DataReader. trong dự án của tôi, tôi đọc datareader và tạo tệp .CSV manualy. trong một vòng lặp tôi đọc datareader và cho mỗi hàng tôi nối thêm giá trị ô vào chuỗi kết quả. cho các cột riêng biệt, tôi sử dụng "," và cho các hàng riêng biệt, tôi sử dụng "\ n". cuối cùng tôi đã lưu chuỗi kết quả là result.csv.

Tôi đề xuất điều này high performance extension. tôi đã thử nghiệm và xuất nhanh 600.000 hàng dưới dạng .CSV.

+0

Trong khi liên kết này có thể trả lời câu hỏi, nó là tốt hơn để bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. - [Từ đánh giá] (/ đánh giá/chất lượng thấp-bài viết/16209261) –

+0

Cảm ơn bạn đã bình luận của bạn. Tôi đã hoàn thành câu trả lời của mình – Nigje

Các vấn đề liên quan