CSVを読込み別のCSVに書き込み への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/11/26 23:15:22
> 今度は、Linq を使わずに、ループで処理する手法で書いてみました。
JET/ACE の Text-IISAM 経由で、クロス集計クエリー(TRANSFORM ステートメント)を利用する例。
JET/ACE の Text-IISAM 経由で、クロス集計クエリー(TRANSFORM ステートメント)を利用する例。
Imports System.Data.OleDb
Public Class Form1
Private tbl As DataTable
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim csvFolder As String = "C:\temp\"
Dim srcFile As String = "1.csv"
Dim sb As New OleDbConnectionStringBuilder()
'sb.Provider = "Microsoft.JET.OLEDB.4.0"
sb.Provider = "Microsoft.ACE.OLEDB.12.0"
sb.DataSource = csvFolder
sb("Extended Properties") = "Text;HDR=No;FMT=Delimited;"
Using conn As New OleDbConnection(sb.ConnectionString)
conn.Open()
Dim s As String = "TRANSFORM SUM(F3) " _
& "SELECT F1 AS `名前` " _
& "FROM `" & srcFile & "` " _
& "GROUP BY F1 " _
& "PIVOT F2"
's &= " IN ('国語','数学','英語')"
tbl = New DataTable(srcFile.Replace("."c, "#"c))
Using adp As New OleDbDataAdapter(s, conn)
adp.Fill(tbl)
End Using
conn.Close()
End Using
'確認用。
DataGridView1.ReadOnly = True
DataGridView1.DataSource = tbl
End Sub
End Class
投稿者 PAPA  (社会人)
投稿日時
2012/11/26 22:29:51
魔界の仮面弁士 様。
色々なパターン有難うございました。
この掲示板に投稿する前に2週間トライして全くできませんでした。
魔界の仮面弁士様に教えて頂き、本当に感謝しております。
お忙しい中、本当に有難う御座いました。
これからVBをもっと勉強します。
色々なパターン有難うございました。
この掲示板に投稿する前に2週間トライして全くできませんでした。
魔界の仮面弁士様に教えて頂き、本当に感謝しております。
お忙しい中、本当に有難う御座いました。
これからVBをもっと勉強します。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/11/26 22:07:34
> いろいろな書き方があるとは思いますが、Linq を使った例をひとつ。
今度は、Linq を使わずに、ループで処理する手法で書いてみました。
『CSVをStreamReaderで読み込んで配列データとして行いたいと思ってます。』
という要望に逆らって、あえて今回は System.IO.StreamReader ではなく、
Microsoft.VisualBasic.FileIO.TextFieldParser で読み込ませています。
なお、先に書いたサンプルで出力される csv ファイルのフォーマットは
「レコード末尾に CrLf を付与」という仕様でしたが、今回のサンプルでは
「レコード間が CrLf で区切られる」という仕様に変更してみました。
(出力した csv ファイルの最後に改行があるか無いかの違いです)
今度は、Linq を使わずに、ループで処理する手法で書いてみました。
『CSVをStreamReaderで読み込んで配列データとして行いたいと思ってます。』
という要望に逆らって、あえて今回は System.IO.StreamReader ではなく、
Microsoft.VisualBasic.FileIO.TextFieldParser で読み込ませています。
Imports System.IO
Imports System.Text
Imports Microsoft.VisualBasic.FileIO
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim srcFile As String = "C:\temp\1.csv"
Dim dstFile As String = "C:\temp\2.csv"
Dim sjis As Encoding = Encoding.GetEncoding("Shift_JIS")
Dim tbl As New DataTable() With {.PrimaryKey = {.Columns.Add("名前")}}
Dim cols = tbl.Columns
Dim rows = tbl.Rows
'csv を読み込んで DataTable を作成。
Using reader As New TextFieldParser(srcFile, sjis)
reader.SetDelimiters(",")
Do Until reader.EndOfData
Dim fields() As String = reader.ReadFields()
If fields.Length <> 3 Then
Continue Do
End If
Dim row = If(rows.Find(fields(0)), rows.Add(fields(0)))
If Not cols.Contains(fields(1)) Then
cols.Add(New DataColumn() With { _
.ColumnName = fields(1), _
.DataType = GetType(Integer), _
.AllowDBNull = False, _
.DefaultValue = 0 _
})
End If
row.SetField(fields(1), CInt(fields(2)))
Loop
End Using
'確認用。今回の変換処理とは無関係。
DataGridView1.ReadOnly = True
DataGridView1.DataSource = tbl
'読み取った DataTable を csv 保存。
Using writer As New StreamWriter(dstFile, False, sjis)
'ヘッダー部
For c As Integer = 0 To cols.Count - 2
writer.Write(cols(c).ColumnName)
writer.Write(","c)
Next
writer.Write(cols(cols.Count - 1).ColumnName)
'データ本体部
For Each row As DataRow In rows
For Each col As DataColumn In cols
If col.ColumnName = "名前" Then
writer.WriteLine()
writer.Write(row(col))
Continue For
End If
writer.Write(","c)
writer.Write(row(col))
Next
Next
writer.Close()
End Using
End Sub
End Class
なお、先に書いたサンプルで出力される csv ファイルのフォーマットは
「レコード末尾に CrLf を付与」という仕様でしたが、今回のサンプルでは
「レコード間が CrLf で区切られる」という仕様に変更してみました。
(出力した csv ファイルの最後に改行があるか無いかの違いです)
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/11/26 21:08:41
>> やりたい事が、バッチリ出来ました。本当に有難う御座いました。
『CSVをStreamReaderで読み込んで配列データとして行いたいと思ってます。』
という条件は満たせていないですけれどね。
> なお、DataTable を DataGridView にバインドしている場合は、
> DataGridView のセル内容を列挙するのではなく、
> DataTable の中身を取り出すようにした方が良いでしょう。
DataGridView を用いず、 DataTable の中身を csv に保存してみました。
今回は File.WriteAllText と File.AppendAllLines を使ってみました。
この方法だと、ファイルを作成した後、追記モードで開きなおす形になるので、
本当は StreamWriter を使う方法や、File.WriteAll 系メソッド一回で書く方が
良いとは思いますが、こういう書き方もあるということで。
『CSVをStreamReaderで読み込んで配列データとして行いたいと思ってます。』
という条件は満たせていないですけれどね。
> なお、DataTable を DataGridView にバインドしている場合は、
> DataGridView のセル内容を列挙するのではなく、
> DataTable の中身を取り出すようにした方が良いでしょう。
DataGridView を用いず、 DataTable の中身を csv に保存してみました。
今回は File.WriteAllText と File.AppendAllLines を使ってみました。
この方法だと、ファイルを作成した後、追記モードで開きなおす形になるので、
本当は StreamWriter を使う方法や、File.WriteAll 系メソッド一回で書く方が
良いとは思いますが、こういう書き方もあるということで。
Private tbl As DataTable 'ここにデータを読み込んでおくこと
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim dstFile As String = "C:\temp\2.csv"
Dim sjis As Encoding = Encoding.GetEncoding("Shift_JIS")
'ヘッダ行の書き込み
File.WriteAllText(dstFile, _
String.Join(","c, tbl.Columns.Cast(Of DataColumn) _
.Select(Function(col) col.ColumnName)), sjis)
'データ行の書き込み
File.AppendAllLines(dstFile, _
tbl.AsEnumerable().Select(Function(r) _
String.Join(","c, r.ItemArray)), sjis)
End Sub
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/11/26 20:20:59
> DataGridViewに表示した後に、DataGridViewの内容をCSVに書き込む
こんな感じでしょうか。
なお、DataTable を DataGridView にバインドしている場合は、
DataGridView のセル内容を列挙するのではなく、
DataTable の中身を取り出すようにした方が良いでしょう。
こんな感じでしょうか。
なお、DataTable を DataGridView にバインドしている場合は、
DataGridView のセル内容を列挙するのではなく、
DataTable の中身を取り出すようにした方が良いでしょう。
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim dstFile As String = "C:\temp\2.csv"
Dim sjis As Encoding = Encoding.GetEncoding("Shift_JIS")
Using stm As New StreamWriter(dstFile, False, sjis)
'ヘッダ行の書き込み
Dim header = From col In DataGridView1.Columns.Cast(Of DataGridViewColumn)() _
Select col.HeaderText
stm.WriteLine(String.Join(",", header))
'データ行の書き込み
For Each row In From r In DataGridView1.Rows.Cast(Of DataGridViewRow)() _
Where Not r.IsNewRow
Dim contents = From cell In row.Cells.Cast(Of DataGridViewCell)() Select cell.Value
stm.WriteLine(String.Join(",", contents))
Next
stm.Close()
End Using
End Sub
投稿者 PAPA  (社会人)
投稿日時
2012/11/26 19:38:02
初めまして、魔界の仮面弁士 様。
やりたい事が、バッチリ出来ました。本当に有難う御座いました。
もう一つ、ご質問ですが、DataGridViewに表示した後に、DataGridViewの内容をCSVに書き込む
方法を教えて頂けると嬉しいです。
お忙しい中、すみませんが宜しくお願い致します。
やりたい事が、バッチリ出来ました。本当に有難う御座いました。
もう一つ、ご質問ですが、DataGridViewに表示した後に、DataGridViewの内容をCSVに書き込む
方法を教えて頂けると嬉しいです。
お忙しい中、すみませんが宜しくお願い致します。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/11/26 18:52:24
DataTable 案です。
先の例との差別化のため、同じ科目を複数回受けた場合は、
後で受けた値が有効となるようにしてみました。
該当する科目を受講していない場合、0ではなく空欄になります。
先の回答では File.ReadLines メソッドを使っていますが、
今回は File.ReadAllLines メソッドを利用しています。
先の例との差別化のため、同じ科目を複数回受けた場合は、
後で受けた値が有効となるようにしてみました。
該当する科目を受講していない場合、0ではなく空欄になります。
先の回答では File.ReadLines メソッドを使っていますが、
今回は File.ReadAllLines メソッドを利用しています。
Imports System.IO
Imports System.Text
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim srcFile As String = "C:\temp\1.csv"
Dim sjis As Encoding = Encoding.GetEncoding("Shift_JIS")
'元のcsvを読み込む
Dim src = From row In File.ReadAllLines(srcFile, sjis)
Where row <> "" Let cols = row.Split(",")
Select New With {.姓 = cols(0), .科目 = cols(1), .点数 = CInt(cols(2))}
'必要な科目分の列を持ったDataTableを用意
Dim tbl As New DataTable()
tbl.PrimaryKey = {tbl.Columns.Add("姓")}
For Each col In From row In src Select row.科目 Distinct
tbl.Columns.Add(col, GetType(Integer))
Next
'DataTableに格納
For Each r In src
Dim row = If(tbl.Rows.Find(r.姓), tbl.Rows.Add(r.姓))
row(r.科目) = r.点数
Next
'DataGridView に表示
DataGridView1.DataSource = tbl
End Sub
End Class
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2012/11/26 18:27:01
いろいろな書き方があるとは思いますが、Linq を使った例をひとつ。
・行の並び順は自由です。英数国でも数国英でも構いませんし、科目順でも名前順でも OK です。
・該当する科目が記入されていなかった場合、その科目は0点となります。
・人と科目が重複する組合せがあった場合、その人の点数は各行の合算値となります。
・行の並び順は自由です。英数国でも数国英でも構いませんし、科目順でも名前順でも OK です。
・該当する科目が記入されていなかった場合、その科目は0点となります。
・人と科目が重複する組合せがあった場合、その人の点数は各行の合算値となります。
Imports System.IO
Imports System.Text
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim srcFile As String = "C:\temp\1.csv"
Dim dstFile As String = "C:\temp\2.csv"
Dim sjis As Encoding = Encoding.GetEncoding("Shift_JIS")
'評価の一覧として読み込む
Dim q = From row In File.ReadLines(srcFile, sjis)
Where row <> "" Let cols = row.Split(",")
Select row = New With {.姓 = cols(0), .科目 = cols(1), .点数 = CInt(cols(2))}
Group By row.姓 Into
国語 = Sum(If(row.科目 = "国語", row.点数, 0)),
数学 = Sum(If(row.科目 = "数学", row.点数, 0)),
英語 = Sum(If(row.科目 = "英語", row.点数, 0))
'ヘッダ付きcsv形式に変換
Dim csv = {"名前,国語,数学,英語"}.Union(q.Select(Function(row) _
String.Format("{0},{1},{2},{3}", row.姓, row.国語, row.数学, row.英語)))
'ファイルに保存する
File.WriteAllLines(dstFile, csv, sjis)
End Sub
End Class
投稿者 YuO  (社会人)
投稿日時
2012/11/26 18:15:38
ミミガーさんが書かれている,DataTbleを使うのが一番簡単だと思いますが……。
一行読んで,
・存在しない教科 (列名) であれば,列を追加する
・存在しない名前 (行の名前列を検索) であれば,行を追加する
・一致する行と列の場所に得点を設定する
を繰り返して最終的なデータを作り,それを元にCSVを書くことになります。
Dictionary(Of String, Dictionary(Of String, Integer))
でも作れなくはないと思いますが……。
# 教科の扱いが面倒になるので……。
一行読んで,
・存在しない教科 (列名) であれば,列を追加する
・存在しない名前 (行の名前列を検索) であれば,行を追加する
・一致する行と列の場所に得点を設定する
を繰り返して最終的なデータを作り,それを元にCSVを書くことになります。
Dictionary(Of String, Dictionary(Of String, Integer))
でも作れなくはないと思いますが……。
# 教科の扱いが面倒になるので……。
投稿者 PAPA  (社会人)
投稿日時
2012/11/26 15:51:32
初めまして初心者のPAPAです。早速、ご連絡頂きありがとうございます。
Excelのマクロ(VBA)ではなくて、VB2010で検討しています。
CSVをStreamReaderで読み込んで配列データとして行いたいと思ってます。
宜しくお願い致します。
Excelのマクロ(VBA)ではなくて、VB2010で検討しています。
CSVをStreamReaderで読み込んで配列データとして行いたいと思ってます。
宜しくお願い致します。
投稿者 ミミガー  (社会人)
投稿日時
2012/11/26 15:40:45
これはVB2010でやるよりは、Excelのマクロ(VBA)を使用した方が手っ取り早いと思いますが...
少なくとも、CSVをDataTableのような形式で読み込む(それが難しいなら配列データとして読み込む)ことができないと、次工程(名前で科目別点数の表を作成)に進むことができませんが、その点はどうなのでしょうか?
少なくとも、CSVをDataTableのような形式で読み込む(それが難しいなら配列データとして読み込む)ことができないと、次工程(名前で科目別点数の表を作成)に進むことができませんが、その点はどうなのでしょうか?
投稿者 PAPA  (社会人)
投稿日時
2012/11/26 15:29:51
初めまして初心者のPAPAです。早速、ご連絡頂きありがとうございます。
条件ですが、下記の様になります。
・教科は3教科だけなのか? ⇒ 3教科以上ある場合があります。
・人によって無い教科があるのか? ⇒ あります。
・教科の並びに条件はあるのか? ⇒ ありません。固定です。
条件等、詳しく記載してなくてすみません。
宜しくお願い致します。
条件ですが、下記の様になります。
・教科は3教科だけなのか? ⇒ 3教科以上ある場合があります。
・人によって無い教科があるのか? ⇒ あります。
・教科の並びに条件はあるのか? ⇒ ありません。固定です。
条件等、詳しく記載してなくてすみません。
宜しくお願い致します。
投稿者 ヴァン  (社会人)
投稿日時
2012/11/26 15:11:32
こんにちは。
・教科は3教科だけなのか?
・人によって無い教科があるのか?
・教科の並びに条件はあるのか?
この辺りの条件はどうなのでしょうか?
・教科は3教科だけなのか?
・人によって無い教科があるのか?
・教科の並びに条件はあるのか?
この辺りの条件はどうなのでしょうか?
投稿者 PAPA  (社会人)
投稿日時
2012/11/26 14:03:05
VB2010初心者です。
vb.net2010でCSVファイルを変換して新しいCSVファイルを作りたいのですが、どのようにすれば良いかヒントを教えていただけないでしょうか?
佐藤,国語,70
高橋,国語,80
鈴木,国語,90
佐藤,数学,75
高橋,数学,85
鈴木,数学,90
佐藤,英語,50
高橋,英語,55
鈴木,英語,60
この様なCSVファイルを変換して
名前,国語,数学,英語
佐藤,70,75,80
高橋,80,85,55
鈴木,90,90,60
という表のようなCSVファイルを作りたいのです。配列を使って行うのでしょうか
ヒントだけでも良いのでよろしくお願いいたします。
vb.net2010でCSVファイルを変換して新しいCSVファイルを作りたいのですが、どのようにすれば良いかヒントを教えていただけないでしょうか?
佐藤,国語,70
高橋,国語,80
鈴木,国語,90
佐藤,数学,75
高橋,数学,85
鈴木,数学,90
佐藤,英語,50
高橋,英語,55
鈴木,英語,60
この様なCSVファイルを変換して
名前,国語,数学,英語
佐藤,70,75,80
高橋,80,85,55
鈴木,90,90,60
という表のようなCSVファイルを作りたいのです。配列を使って行うのでしょうか
ヒントだけでも良いのでよろしくお願いいたします。
魔界の仮面弁士様、ミミガー様、Yuo様、色々とアドバイスを頂き有難うございました。
また、初歩的なご質問をするかも知れませんが、その際には宜しくお願い致します。