দৃ CS়ভাবে টাইপ করা ডেটা স্ট্রাকচারে কোনও সিএসভি ফাইল আমদানির সর্বোত্তম উপায় কী?
দৃ CS়ভাবে টাইপ করা ডেটা স্ট্রাকচারে কোনও সিএসভি ফাইল আমদানির সর্বোত্তম উপায় কী?
উত্তর:
মাইক্রোসফ্টের টেক্সটফিল্ড পার্সার স্থিতিশীল এবং সিএসভি ফাইলগুলির জন্য আরএফসি 4180 অনুসরণ করে। Microsoft.VisualBasic
নেমস্পেসের কাছ থেকে দূরে থাকবেন না ; এটি। নেট ফ্রেমওয়ার্কের একটি স্ট্যান্ডার্ড উপাদান, কেবলমাত্র বিশ্ব Microsoft.VisualBasic
সমাবেশে একটি রেফারেন্স যুক্ত করুন ।
যদি আপনি উইন্ডোজের জন্য সংকলন করে থাকেন (মনো-এর বিপরীতে) এবং "ভাঙ্গা" (আর-এফসিএফ-কমপ্লায়েন্ট) সিএসভি ফাইলগুলি বিশ্লেষণ করার প্রত্যাশা করেন না, তবে এটি সুস্পষ্ট পছন্দ হবে, কারণ এটি নিখরচায়, অবিচ্ছিন্ন, স্থিতিশীল, এবং সক্রিয়ভাবে সমর্থিত, যার বেশিরভাগ ফাইলহেলপারদের জন্য বলা যায় না।
আরও দেখুন: কীভাবে: ভিজুয়াল বেসিকের কমা-বিসীমাংসিত পাঠ্য ফাইলগুলি থেকে কোনও ভিবি কোড উদাহরণের জন্য পড়ুন।
TextFieldParser
ট্যাব-সীমাবদ্ধ এবং অন্যান্য অদ্ভুত এক্সেল-উত্পাদিত ক্রাফ্টের জন্যও কাজ করবে। আমি বুঝতে পেরেছি যে আপনার পূর্ববর্তী উত্তরটি দাবি করছিল না যে গ্রন্থাগারটি ভিবি-নির্দিষ্ট ছিল, এটি কেবলমাত্র আমার কাছে বোঝানো হয়েছিল যে এটি সত্যিকার অর্থেই ভিবির জন্য, এবং সি # থেকে ব্যবহার করার উদ্দেশ্যে নয় , যা আমি মনে করি না কেস - এমএসভিবিতে সত্যই দরকারী কিছু ক্লাস রয়েছে।
একটি OleDB সংযোগ ব্যবহার করুন।
String sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\InputDirectory\\;Extended Properties='text;HDR=Yes;FMT=Delimited'";
OleDbConnection objConn = new OleDbConnection(sConnectionString);
objConn.Open();
DataTable dt = new DataTable();
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM file.csv", objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
objAdapter1.Fill(dt);
objConn.Close();
আপনি যদি সিএসভি পার্সিংয়ের জন্য মোটামুটি জটিল পরিস্থিতিতে প্রত্যাশা করে থাকেন তবে আমাদের নিজস্ব পার্সার ঘূর্ণায়মানটি ভাবেন না । সেখানে চমৎকার সরঞ্জাম অনেক, মত FileHelpers , অথবা থেকেও বেশী CodeProject ।
মুল বক্তব্যটি হ'ল এটি একটি মোটামুটি সাধারণ সমস্যা এবং আপনি বাজি ধরতে পারেন যে অনেক সফ্টওয়্যার বিকাশকারী ইতিমধ্যে এই সমস্যাটি সম্পর্কে চিন্তাভাবনা করেছেন এবং সমাধান করেছেন।
ব্রায়ান দৃ strongly়ভাবে টাইপ করা সংগ্রহে রূপান্তর করার জন্য একটি দুর্দান্ত সমাধান দেয় gives
প্রদত্ত বেশিরভাগ CSV পার্সিংয়ের পদ্ধতিগুলি পালানোর ক্ষেত্রগুলি বা CSV ফাইলের অন্যান্য সূক্ষ্মতাগুলিকে (ট্রিমিং ফিল্ডের মতো) বিবেচনা করে না। আমি ব্যক্তিগতভাবে ব্যবহার করি কোডটি এখানে। এটি প্রান্তের চারপাশে কিছুটা রুক্ষ এবং এতে কোনও ত্রুটি প্রতিবেদন করার ক্ষমতা নেই।
public static IList<IList<string>> Parse(string content)
{
IList<IList<string>> records = new List<IList<string>>();
StringReader stringReader = new StringReader(content);
bool inQoutedString = false;
IList<string> record = new List<string>();
StringBuilder fieldBuilder = new StringBuilder();
while (stringReader.Peek() != -1)
{
char readChar = (char)stringReader.Read();
if (readChar == '\n' || (readChar == '\r' && stringReader.Peek() == '\n'))
{
// If it's a \r\n combo consume the \n part and throw it away.
if (readChar == '\r')
{
stringReader.Read();
}
if (inQoutedString)
{
if (readChar == '\r')
{
fieldBuilder.Append('\r');
}
fieldBuilder.Append('\n');
}
else
{
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder = new StringBuilder();
records.Add(record);
record = new List<string>();
inQoutedString = false;
}
}
else if (fieldBuilder.Length == 0 && !inQoutedString)
{
if (char.IsWhiteSpace(readChar))
{
// Ignore leading whitespace
}
else if (readChar == '"')
{
inQoutedString = true;
}
else if (readChar == ',')
{
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder = new StringBuilder();
}
else
{
fieldBuilder.Append(readChar);
}
}
else if (readChar == ',')
{
if (inQoutedString)
{
fieldBuilder.Append(',');
}
else
{
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder = new StringBuilder();
}
}
else if (readChar == '"')
{
if (inQoutedString)
{
if (stringReader.Peek() == '"')
{
stringReader.Read();
fieldBuilder.Append('"');
}
else
{
inQoutedString = false;
}
}
else
{
fieldBuilder.Append(readChar);
}
}
else
{
fieldBuilder.Append(readChar);
}
}
record.Add(fieldBuilder.ToString().TrimEnd());
records.Add(record);
return records;
}
মনে রাখবেন যে এটি ক্ষেত্রগুলির প্রান্তের কেসটি ডাবল কোট দ্বারা সীমাবদ্ধ নয়, তবে মেরিলির ভিতরে একটি উদ্ধৃত স্ট্রিং রয়েছে handle কিছুটা আরও ভাল সম্প্রসারণের পাশাপাশি কিছু সঠিক লাইব্রেরির লিঙ্কগুলির জন্য এই পোস্টটি দেখুন ।
আমি @ সাথে একমত NotMyself । ফাইলহেলপার্স ভালভাবে পরীক্ষিত এবং প্রকারের সমস্ত ধরণের কেসগুলি পরিচালনা করে যা আপনি নিজেই যদি করেন তবে শেষ পর্যন্ত আপনাকে মোকাবেলা করতে হবে। ফাইলহেল্পাররা কী করে তা একবার দেখুন এবং কেবল আপনার নিজের লিখুন যদি আপনি একেবারে নিশ্চিত হন যে (1) আপনার কখনও ফাইলহেল্পারদের প্রান্তের কেসগুলি পরিচালনা করার প্রয়োজন হবে না, বা (2) আপনি এই ধরণের স্টাফ লিখতে পছন্দ করেন এবং যাচ্ছেন আপনি যখন এই জাতীয় জিনিসগুলি বিশ্লেষণ করতে চান তখন আনন্দিত হন:
1, "বিল", "স্মিথ", "সুপারভাইজার", "কোনও মন্তব্য নেই"
2, 'ড্রেক,', 'ও'ম্যালি', "জানিটর,
উফফ, আমার উদ্ধৃতি নেই এবং আমি একটি নতুন লাইনে আছি!
আমি বিরক্ত হয়ে পড়েছিলাম তাই আমি আমার কিছু জিনিস সংশোধন করেছি। এটি একটি ওও পদ্ধতিতে পার্সিংকে ফাইলের মাধ্যমে পুনরাবৃত্তির পরিমাণ হ্রাস করার চেষ্টা করে, এটি শীর্ষের অগ্রভাগে কেবল একবারে পুনরাবৃত্তি করে।
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// usage:
// note this wont run as getting streams is not Implemented
// but will get you started
CSVFileParser fileParser = new CSVFileParser();
// TO Do: configure fileparser
PersonParser personParser = new PersonParser(fileParser);
List<Person> persons = new List<Person>();
// if the file is large and there is a good way to limit
// without having to reparse the whole file you can use a
// linq query if you desire
foreach (Person person in personParser.GetPersons())
{
persons.Add(person);
}
// now we have a list of Person objects
}
}
public abstract class CSVParser
{
protected String[] deliniators = { "," };
protected internal IEnumerable<String[]> GetRecords()
{
Stream stream = GetStream();
StreamReader reader = new StreamReader(stream);
String[] aRecord;
while (!reader.EndOfStream)
{
aRecord = reader.ReadLine().Split(deliniators,
StringSplitOptions.None);
yield return aRecord;
}
}
protected abstract Stream GetStream();
}
public class CSVFileParser : CSVParser
{
// to do: add logic to get a stream from a file
protected override Stream GetStream()
{
throw new NotImplementedException();
}
}
public class CSVWebParser : CSVParser
{
// to do: add logic to get a stream from a web request
protected override Stream GetStream()
{
throw new NotImplementedException();
}
}
public class Person
{
public String Name { get; set; }
public String Address { get; set; }
public DateTime DOB { get; set; }
}
public class PersonParser
{
public PersonParser(CSVParser parser)
{
this.Parser = parser;
}
public CSVParser Parser { get; set; }
public IEnumerable<Person> GetPersons()
{
foreach (String[] record in this.Parser.GetRecords())
{
yield return new Person()
{
Name = record[0],
Address = record[1],
DOB = DateTime.Parse(record[2]),
};
}
}
}
}
সেখানে একটি সমাধান, একটি ব্যবহার করে কোড প্রদান CodeProject দুটি নিবন্ধ আছে StreamReader এবং এক যে ডেটা আমদানি করে CSV ব্যবহার মাইক্রোসফট টেক্সট ড্রাইভার ।
এটি করার একটি ভাল সহজ উপায় হ'ল ফাইলটি খোলার জন্য এবং প্রতিটি লাইনকে একটি অ্যারে, লিঙ্কযুক্ত তালিকায়, আপনার পছন্দমতো ডেটা-স্ট্রাকচার-এর-মতো করে পড়া। যদিও প্রথম লাইনটি পরিচালনা করার বিষয়ে সতর্কতা অবলম্বন করুন।
এটি আপনার মাথার উপরে থাকতে পারে তবে সংযোগের স্ট্রিং ব্যবহার করে এগুলি অ্যাক্সেস করার সরাসরি উপায় রয়েছে বলে মনে হয় ।
সি # বা ভিবি এর পরিবর্তে পাইথন ব্যবহারের চেষ্টা করবেন না কেন? এটি আমদানি করার জন্য একটি দুর্দান্ত সিএসভি মডিউল রয়েছে যা আপনার জন্য সমস্ত ভারী উত্তোলন করে।
আমাকে এই গ্রীষ্মে গ্রীষ্মের জন্য একটি প্রকল্পের জন্য .NET এ একটি সিএসভি পার্সার ব্যবহার করতে হয়েছিল এবং মাইক্রোসফ্ট জেট টেক্সট ড্রাইভারের সাথে স্থির হয়েছিলেন। আপনি একটি সংযোগ স্ট্রিং ব্যবহার করে একটি ফোল্ডার নির্দিষ্ট করেন, তারপরে একটি এসকিউএল নির্বাচন বিবৃতি ব্যবহার করে কোনও ফাইলকে জিজ্ঞাসা করুন। আপনি একটি স্কিমা.আইএনআই ফাইল ব্যবহার করে শক্তিশালী প্রকারগুলি নির্দিষ্ট করতে পারেন। আমি প্রথমে এটি করিনি, তবে তারপরে আমি খারাপ ফলাফল পাচ্ছিলাম যেখানে আইপি নম্বর বা "এক্সওয়াইকিউ 3.9 এসপি 1" এর মতো একটি এন্ট্রি যেমন ডেটার ধরণটি তত্ক্ষণাত্ প্রকাশিত হয়নি।
আমি যে সীমাবদ্ধতার মধ্যে পড়েছিলাম তা হ'ল এটি কলামের names৪ টি অক্ষরের নাম পরিচালনা করতে পারে না; এটি কেটে যায়। আমি খুব খারাপভাবে ডিজাইন করা ইনপুট ডেটা নিয়ে কাজ করছি, এ ছাড়া এটি কোনও সমস্যা হবেনা। এটি একটি ADO.NET ডেটাসেট প্রদান করে।
এটিই আমি খুঁজে পেল সেরা সমাধান। আমি আমার নিজের সিএসভি পার্সার রোলিংয়ের বিষয়ে সতর্ক থাকব, যেহেতু আমি সম্ভবত শেষের কয়েকটিটি মিস করব এবং আমি নেট খুঁজে বের করার জন্য অন্য কোনও ফ্রি সিএসভি পার্সিং প্যাকেজ পাইনি।
সম্পাদনা: এছাড়াও, প্রতি ডিরেক্টরি প্রতি কেবল একটি স্কিমা.ইএনআই ফাইল থাকতে পারে, তাই আমি প্রয়োজনীয় কলামগুলি দৃ strongly়ভাবে টাইপ করার জন্য এটিতে গতিশীলভাবে যুক্ত করেছিলাম। এটি নির্দিষ্ট করা কলামগুলিকে কেবল দৃ strongly়-টাইপ করবে এবং কোনও অনির্দিষ্ট ক্ষেত্রের জন্য অনুমান করবে। আমি সত্যিই এটির প্রশংসা করেছি, যেহেতু আমি একটি তরল 70+ কলাম সিএসভি আমদানির বিষয়ে কাজ করছি এবং প্রতিটি কলামটি কেবলমাত্র দুর্ব্যবহারকে নির্দিষ্ট করতে চাইনি।
আমি কিছু কোড টাইপ করেছি। ডাটাগ্রিডভিউয়ারের ফলাফলটি ভাল লাগছিল। এটি বস্তুর অ্যারেলিস্টে পাঠ্যের একক লাইনকে পার্স করে।
enum quotestatus
{
none,
firstquote,
secondquote
}
public static System.Collections.ArrayList Parse(string line,string delimiter)
{
System.Collections.ArrayList ar = new System.Collections.ArrayList();
StringBuilder field = new StringBuilder();
quotestatus status = quotestatus.none;
foreach (char ch in line.ToCharArray())
{
string chOmsch = "char";
if (ch == Convert.ToChar(delimiter))
{
if (status== quotestatus.firstquote)
{
chOmsch = "char";
}
else
{
chOmsch = "delimiter";
}
}
if (ch == Convert.ToChar(34))
{
chOmsch = "quotes";
if (status == quotestatus.firstquote)
{
status = quotestatus.secondquote;
}
if (status == quotestatus.none )
{
status = quotestatus.firstquote;
}
}
switch (chOmsch)
{
case "char":
field.Append(ch);
break;
case "delimiter":
ar.Add(field.ToString());
field.Clear();
break;
case "quotes":
if (status==quotestatus.firstquote)
{
field.Clear();
}
if (status== quotestatus.secondquote)
{
status =quotestatus.none;
}
break;
}
}
if (field.Length != 0)
{
ar.Add(field.ToString());
}
return ar;
}
আপনি যদি গ্যারান্টি দিতে পারেন যে ডেটাতে কোনও কমা নেই, তবে সবচেয়ে সহজ উপায় সম্ভবত স্ট্রিং.স্প্লিট ব্যবহার করা হবে ।
উদাহরণ স্বরূপ:
String[] values = myString.Split(',');
myObject.StringField = values[0];
myObject.IntField = Int32.Parse(values[1]);
আপনি সাহায্যের জন্য ব্যবহার করতে পারেন এমন গ্রন্থাগার থাকতে পারে, তবে এটি সম্ভবত আপনি যতটা সহজ পেতে পারেন। কেবলমাত্র আপনার ডেটাতে কমা থাকতে পারে তা নিশ্চিত করুন, অন্যথায় আপনার আরও ভাল পার্স করা দরকার।