จำนวนความยาวของ string ตอนเป็น UTF-8 ไม่เท่ากับตอนเป็น ANSI ครับ
แล้ว Winapp นี่อ่านได้เหมือนกันป่าวครับ
Date :
2015-07-20 16:38:35
By :
lamaka.tor
บรรทัดที่ 2 ถึง 18 จะบอกว่าเป็น field อะไร ขนาด field กว้างเท่าไหร่ และเริ่มที่ ตัวอักษรที่เท่าไร ครับ
จริงๆ แล้วข้อมูลมันเป็น text บรรทัดเดียวยาวต่อเนื่องกันไป ผมตัดมาให้ดูแบบง่ายๆ ครับ
พอความกว้างของ filed ผิด ทำให้ตำแหน่งเริ่มต้นของ field ผิดไปด้วยครับ
win app อ่านได้ครับ แต่ถ้าเจอตำแหน่งผิด มันจะขึ้น error ทันที
แต่มันโชว์นะครับว่า ไฟล์ที่อ่านเข้าไปมีข้อมูลอะไรบ้าง แต่ตำแหน่ง start ของแต่ละ field ผิด มันจะไม่ import ข้อมูลให้
ที่เห็นเป็นภาษาต่างดาว คือ ANSI นะครับ Win App มันไปแปลงเป็น UTF อีกทีหลัง import แล้ว
Date :
2015-07-20 18:38:44
By :
Aod47
Import Export เป็นคนเขียนเองทั้งสองขารึเปล่า
แค่สงสัยทำไมไม่ Save เป็น UTF-8 ไปเลย
Date :
2015-07-20 19:19:44
By :
watcharop
Export เขียนเองครับ Export จาก Web App ซึ่งเขียนด้วย ASP.Net C#
Win App ซื้อมา เป็นระบบปิด ค่อนข้างจะ legacy แล้ว ตอนนี้ ใช้คู่ขนานกันอยู่
กะว่า Web App เสร็จทุก Module ก็จะเสนอผู้บริหาร ขอยกเลิกใช้ Win App
ทีนี้จะลดงาน copy ข้อมูลจาก Web App มาแปะที่ Win App
เห็นว่า Win App มี Import ข้อมูล ก็เลยลอง Import เข้า Win App ครับ
ที่ไม่ใช้ UTF-8 เพราะว่า ไฟล์ต้นแบบของ Win App มันเป็น ANSI ครับ
Date :
2015-07-20 20:47:36
By :
Aod47
แล้วจริงๆ ไอ้ตัวแปลกๆ มันคือภาษาไทยรึเปล่า
ถ้าใช่ ขอดูโค้ดส่วน Export หน่อย ถ้าไม่ใช่ความลับ
Date :
2015-07-20 21:04:01
By :
watcharop
ผมเจอ code แปลงไฟล์ utf-8 เป็น ANSI จากที่นี่ครับ http://bytes.com/topic/c-sharp/answers/865205-how-convert-utf8-file-into-ansi
Code (C#)
string filePath = "c:\\test.txt";
// Reads UTF8 file
StreamReader fileStream = new StreamReader(filePath);
string fileContent = fileStream.ReadToEnd();
fileStream.Close();
// Now writes the content in ANSI
StreamWriter ansiWriter = new StreamWriter(filePath.Replace(".txt", "-ansi.txt"), false, Encoding.GetEncoding(1250));
ansiWriter.Write(fileContent);
ansiWriter.Close();
ที่ผมอยากทำคือ แปลงชุด string ที่อ่านจาก db จาก Web App (ซึ่งตรงนี้ผมเข้าใจว่าเป็น utf-8) ให้เป็น ANSI ก่อน
แล้วนับความยาว string ANSI เพื่อไปกำหนดตัวเลขใน column 2 กับ 3 ของ บรรทัดที่ 2-18
จึงจะสามารถ Import ไฟล์นี้เข้าไปที่ Win App ได้อย่างถูกต้องครับ
Date :
2015-07-20 21:08:48
By :
Aod47
ถ้าตัวแปลกๆ นั่นคือภาษาไทย ให้เลือก Encoding 874
Code (VB.NET)
...
dim dread as SqlDataReader = cmd.ExecuteReader()
...
StreamWriter ansiWriter = new StreamWriter("test.txt", false, Encoding.GetEncoding(874))
dim sb as new System.Text.StringBuilder
Do While dread.read()
sb.Clear()
...
sb.AppendFormat("{0}{1}",dread("x1"),dread("x2"))
...
ansiWriter.WriteLine(sb.ToString())
End While
ansiWriter.Close();
Date :
2015-07-20 21:24:26
By :
watcharop
กรณีที่ไฟล์คุณเป็น ANSI และเนื้อหาในไฟล์เป็น ภาษาไทย
ต้องเปลี่ยน Language for non-Unicode programs เป็น Thai ด้วย
ถ้าไม่รู้วิธีเปลี่ยน ก็ใช้ google ค้นเลยครับ เมื่อกี้ลองค้นแล้ว ก็เจอวิธีเปลี่ยน
Date :
2015-07-20 21:28:15
By :
watcharop
code มาแล้วครับ พร้อม อัพเดทรูปใหม่
Code (C#)
protected void ExportButton_Click(object sender, DirectEventArgs e)
{
string filename = "K" + Utils.Right(("0000000" + bibId),7) + ".txt";
StringBuilder marc = new StringBuilder();
marc.Append(GetVarField(bibId));
//Download the Text file.
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=" + filename);
Response.Charset = "";
Response.ContentType = "application/vnd.text";
//Response.ContentEncoding = System.Text.Encoding.Unicode;
Response.Cache.SetCacheability(HttpCacheability.NoCache);
System.IO.StringWriter stringWrite = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
Response.Write(marc.ToString());
Response.End();
}
private string GetVarField(string bibId)
{
char cRS = (char)30; // [RS] field terminator
char cUS = (char)31; // [US] delimiter
char cGS = (char)29; // [GS] record terminator
string marc = string.Empty;
string directory = string.Empty;
string varfield = string.Empty;
{ // get Variable Fields Value
int tagStart = 0; // tag 001.Length + tag 003.Length
string queryString = "SELECT * FROM [BibTag_V] WHERE unUsed=0 AND bibId=" + bibId + " ORDER BY tag, tagId";
string connectionString = strConn;
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
SqlDataReader dt;
dt = command.ExecuteReader();
while (dt.Read())
{
string tag = dt["tag"].ToString();
string tagId = dt["tagId"].ToString();
bool isFullstop = bool.Parse(dt["isFullstop"].ToString());
string tagString = string.Empty;
directory += tag;
/* loop Subfield Value */
string querySf = "SELECT * FROM [BibSubfield_V] WHERE tagId=" + tagId + " ORDER BY tag, tagId, sorder";
using (SqlConnection conSf = new SqlConnection(connectionString))
{
SqlCommand commandSf = new SqlCommand(querySf, conSf);
commandSf.Connection.Open();
commandSf.ExecuteNonQuery();
SqlDataReader dtSf;
dtSf = commandSf.ExecuteReader();
while (dtSf.Read())
{
string sCode = dtSf["scode"].ToString();
string sValue = dtSf["svalue"].ToString();
string sPrefix = dtSf["prefixSymbol"].ToString();
string sOrder = dtSf["sorder"].ToString();
if (tag != "008")
{
if (sOrder == "1")
{ // add only cUS
varfield += cUS;
tagString += cUS;
}
else
{ // add prefix & cUS
if (!string.IsNullOrEmpty(sPrefix))
{
varfield += sPrefix + " ";
tagString += sPrefix + " ";
}
varfield += cUS;
tagString += cUS;
}
varfield += sCode;
tagString += sCode;
}
varfield += sValue;
tagString += sValue;
}
{ // check last fullstop
string ft = Utils.Right(tagString, 1);
if (ft != ".")
{
if (isFullstop)
{
varfield += ".";
tagString += ".";
}
}
}
varfield += cRS;
tagString += cRS;
directory += Utils.Right("0000" + tagString.Length.ToString(), 4); // calculate length of field
directory += Utils.Right("00000" + tagStart.ToString(), 5); // calculate starting_chr_position
tagStart += int.Parse(tagString.Length.ToString());
tagString = string.Empty; // clear tagString to inital value
dtSf.Close();
dtSf = null;
}
}
dt.Close();
dt = null;
}
}
/* get Leader */
int i0004 = 24 + int.Parse(directory.Length.ToString()) + 1 +int.Parse(varfield.Length.ToString()) + 1;
// leader.l + directory.l + [RS] + varfield.l + [GS]
string l0004 = Utils.Right("00000" + i0004.ToString(), 5);
string l05 = "n"; // n == new
string l06 = GetTypeOfRecord(bibId);
string l07 = GetBibLevel(bibId);
string l0811 = " a22"; // fixed value
int i1216 = 24 + int.Parse(directory.Length.ToString()) + 1;
// leader.Length + directory.Length + [RS]
string l1216 = Utils.Right("00000" + i1216.ToString() , 5);
string l1719 = " a "; // fixed value
string l2023 = "4500"; // fixed value
string leader = l0004 + l05 + l06 + l07 + l0811 + l1216 + l1719 + l2023;
marc = leader + directory + cRS + varfield + cGS;
return marc;
}
ประเด็นปัญหาของผมไม่ได้อยู่ที่ไฟล์ที่ export ออกมาครับ มัน import ไปเข้า Win App ได้
ประเด็นอยู่ที่ Win App มันจะแจ้ง error ว่า ตำแหน่ง field ที่ระบุไม่ถูกต้อง
ซึ่งเป็นผลมาจากตอนที่วนลูปเพื่อเอาข้อมูลมาต่อๆ กันเป็นไฟล์เดียว
ผมคำนวณตำแหน่งความยาวของแต่ละ field โดยใช้คำสั่ง int.Parse(tagString.Length.ToString());
ซึ่งผมเข้าใจว่า string ในตอนที่วนลูป เป็น utf-8 และความยาวของ string น้อยกว่าตอนที่ export เป็นไฟล์แล้ว ซึ่งเป็น ANSI
ตรงนี้งงมากครับว่าทำไมมันถึงยาวไม่เท่ากัน
ผมคิดว่าวิธีแก้ปัญหาคือ ต้องแปลง string ตัว utf-8 ให้เป็น ANSI ก่อน จึงจะหาความยาวของ string ที่ถูกต้อง
เพื่อระบุกลับไปที่ ส่วน directory ได้ครับ (ส่วนที่ตีกรอบสีไว้ สีแดงคือ field สีเขียว ความกว้าง field และสีน้ำเงินคือ บอกว่าข้อมูลของ field นี้อยู่ที่ character ที่เท่าไหร่ของไฟล์นี้ ครับ)
จากภาพนะครับ field 008, 020, 082 ซึ่งมี char เป็นตัวเลขและภาษาอังกฤษ ความกว้าง filed ถูกต้องตรงกันทั้ง utf-8 และ ANSI
แต่ field หลังจากนั้นข้อมูลเป็นภาษาไทย เช่น filed 100 ตอนคำนวณในโปรแกรม มันกว้างแค่ 23 ตัวอักษร แต่พอมาเปิดดูในไฟล์ ANSI กับกว้างถึง 55 ตัวอักษร (56-1)
ตรงนี้ละครับ ปัญหาของผม
ประวัติการแก้ไข 2015-07-21 07:46:48 2015-07-21 07:50:05
Date :
2015-07-21 07:40:31
By :
Aod47
โทษทีนะครับ
ลอง replace("","/") แต่ละแถวดูได้ไม๊ครับ
ถ้าเรารู้ระยะห่างของช่องว่างแต่ละแถวน่าจะแก้ไขได้ง่ายขึ้นครับ
ปกติผมใช้โค๊ดนี้ยุครับไม่มีปัญหา(สำหรับงานผม) ลองเอาไปเล่นๆดูครับ
Code (C#)
public static System.Collections.Generic.List<string> textFileReaderFormline(string pathFileName)
{
System.Collections.Generic.List<string> list = new System.Collections.Generic.List<string>();
System.IO.StreamReader fs;
fs = new System.IO.StreamReader(pathFileName, System.Text.Encoding.GetEncoding(874));
string line;
while ((line = fs.ReadLine()) != null)
{
list.Add(line);
}
return list;
}
Date :
2015-07-21 08:37:42
By :
lamaka.tor
ไม่รู้ว่าช่วยอะไรได้หรือเปล่า
แต่โค้ดนี้ จะสร้าง TextFile ขนาด 10 bytes
Code (VB.NET)
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Dim sLine As String = "ข้าวมันไก่"
Response.Clear()
Response.ContentEncoding = Encoding.GetEncoding(874)
Response.AddHeader("content-disposition", "attachment;filename=test.txt")
Response.ContentType = "application/vnd.text"
Response.Write(sLine)
Response.End()
End Sub
Date :
2015-07-21 08:48:50
By :
watcharop
ประวัติการแก้ไข 2015-07-21 08:52:48 2015-07-21 08:53:47
Date :
2015-07-21 08:51:51
By :
watcharop
ขอบคุณครับ ทั้งสองท่าน
ตอนนี้ผมละมึนตึ๊บ คิดว่าน่าจะเป็นที่ภาษาไทย กับ ANSI ครับ
เพราะลองกับไฟล์ที่เป็นภาษาอังกฤษล้วน ทีเดียวผ่านเลย ข้อมูลมาครบหมดไม่ตกหล่น
ขอลองวิธี byte count ก่อนนะครับ ได้ผลยังไงจะมาบอกอีกที
ประวัติการแก้ไข 2015-07-21 09:07:52
Date :
2015-07-21 09:03:50
By :
Aod47
ไม่ได้ลองครับผม พอดีได้ประกายเรื่อง byte count จากคุณหางอึ่งครับ
แล้วก็เป็นอย่างนั้นจริงๆ ครับ พอใช้ byte count ทีเดียวผ่านเลยครับ ภาษาไทย
code ที่ต้องนับจำนวนตัวอักษรผมเปลี่ยนมาเป็น
Code (C#)
int tagStringLen = Encoding.UTF8.GetByteCount(tagString);
int directoryLen = Encoding.UTF8.GetByteCount(directory);
int varfieldLen = Encoding.UTF8.GetByteCount(varfield);
จะได้ความยาวเป็น byte ออกมา
ขอบคุณมากครับทั้งสองท่าน
Date :
2015-07-21 09:44:55
By :
Aod47
ยินดีด้วยครับ
Date :
2015-07-21 09:57:45
By :
lamaka.tor
Load balance : Server 01