回答編集履歴

4

サンプル提示

2016/01/29 04:42

投稿

hsk
hsk

スコア728

test CHANGED
@@ -1,3 +1,257 @@
1
+ 文字列の操作(Replaceなど)は、結構重い処理になります。
2
+
3
+ バイト志向でCSVファイルを解析することが、解析に関しては一番速く処理できそうです。一度、こちらのコードを実行していただいて、その速度がどんなものか試されると、マシンスペック上の限界を知るご参考になるかもしれません。
4
+
5
+
6
+
7
+ (Windowsフォームにボタンを貼っています)
8
+
9
+ ```VB
10
+
11
+ Public Class Form1
12
+
13
+ Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
14
+
15
+ Dim sjisEncoding As System.Text.Encoding = System.Text.Encoding.GetEncoding(932)
16
+
17
+
18
+
19
+ Dim filePath As String = "C:\SAMPLE_SJIS.CSV" ' 入力ファイルパス
20
+
21
+ Dim result As List(Of Object) = New List(Of Object) ' 出力データ
22
+
23
+
24
+
25
+ Dim readHeader As Boolean = False ' ヘッダ行を読み終わったらTrue
26
+
27
+
28
+
29
+ Using fs As New System.IO.FileStream(filePath, IO.FileMode.Open)
30
+
31
+ Dim record As List(Of String) = New List(Of String)
32
+
33
+ Dim byteBuffer(256) As Byte
34
+
35
+ Dim byteBufferPosition As Integer = 0
36
+
37
+ Dim inQuotes As Boolean = False
38
+
39
+ Dim leadingByteData As Byte = 0
40
+
41
+ Dim byteData As Integer
42
+
43
+
44
+
45
+ Do
46
+
47
+ byteData = fs.ReadByte()
48
+
49
+ If byteData = -1 Then Exit Do
50
+
51
+
52
+
53
+ If byteBuffer.Length < byteBufferPosition - 1 Then Throw New ApplicationException("1フィールドの長さがバッファサイズ付近に達しています") ' -1 は、SJISコード処理などで2バイト書く可能性から
54
+
55
+
56
+
57
+ If IsSJisLeadingByte(leadingByteData) Then
58
+
59
+ ' SHIFT JIS の2バイト目
60
+
61
+ byteBuffer(byteBufferPosition) = leadingByteData
62
+
63
+ byteBufferPosition += 1
64
+
65
+ byteBuffer(byteBufferPosition) = CType(byteData, Byte)
66
+
67
+ byteBufferPosition += 1
68
+
69
+ leadingByteData = 0
70
+
71
+ Continue Do
72
+
73
+ End If
74
+
75
+
76
+
77
+ Select Case byteData
78
+
79
+ Case 10 ' LFコード
80
+
81
+ If leadingByteData = 13 Then ' 1つ前はCR
82
+
83
+ If 0 < byteBufferPosition Then
84
+
85
+ Dim v As String = sjisEncoding.GetString(byteBuffer, 0, byteBufferPosition)
86
+
87
+ record.Add(v)
88
+
89
+ byteBufferPosition = 0
90
+
91
+ leadingByteData = 0
92
+
93
+ End If
94
+
95
+
96
+
97
+ ' 1レコード終了
98
+
99
+ If Not readHeader Then
100
+
101
+ readHeader = True
102
+
103
+ Else
104
+
105
+ result.Add(record)
106
+
107
+ End If
108
+
109
+ record = New List(Of String)
110
+
111
+ Continue Do
112
+
113
+ End If
114
+
115
+ Throw New ApplicationException("不自然な箇所にLFコードが見つかりました")
116
+
117
+ Case 13 ' CRコード
118
+
119
+ If leadingByteData = 34 Then
120
+
121
+ ' 直前は終了の引用符
122
+
123
+ inQuotes = False
124
+
125
+ End If
126
+
127
+ If inQuotes Then Throw New ApplicationException("フィールドの途中にCRコードが見つかりました")
128
+
129
+ leadingByteData = 13
130
+
131
+ Continue Do
132
+
133
+ Case 32 ' 空白
134
+
135
+ If Not inQuotes Then
136
+
137
+ ' 二重引用符内でなければ、無視する
138
+
139
+ Continue Do
140
+
141
+ End If
142
+
143
+ Case 34 ' 二重引用符
144
+
145
+ If Not inQuotes Then
146
+
147
+ ' 開始の引用符
148
+
149
+ inQuotes = True
150
+
151
+ Else
152
+
153
+ If leadingByteData = 34 Then ' 1つ前も二重引用符だった
154
+
155
+ byteBuffer(byteBufferPosition) = 34 ' 1つだけにする
156
+
157
+ byteBufferPosition += 1
158
+
159
+ leadingByteData = 0
160
+
161
+ Else
162
+
163
+ leadingByteData = 34 ' 次まで保留
164
+
165
+ End If
166
+
167
+ End If
168
+
169
+ Continue Do
170
+
171
+ Case 44 ' カンマ
172
+
173
+ If leadingByteData = 34 Then
174
+
175
+ ' 直前は終了の引用符
176
+
177
+ inQuotes = False
178
+
179
+ End If
180
+
181
+ If Not inQuotes Then
182
+
183
+ ' 二重引用符内でなければ、フィールドの区切りとみなす
184
+
185
+ ' byteBuffer(byteBufferPosition) = 0
186
+
187
+ Dim v As String = sjisEncoding.GetString(byteBuffer, 0, byteBufferPosition)
188
+
189
+ record.Add(v)
190
+
191
+ byteBufferPosition = 0
192
+
193
+ leadingByteData = 0
194
+
195
+ Continue Do
196
+
197
+ End If
198
+
199
+ ' 二重引用符内なら、通常の文字扱い
200
+
201
+ End Select
202
+
203
+ If IsSJisLeadingByte(byteData) Then
204
+
205
+ ' SHIFT JIS の1バイト目
206
+
207
+ leadingByteData = CType(byteData, Byte)
208
+
209
+ Continue Do
210
+
211
+ End If
212
+
213
+
214
+
215
+ ' 1バイト文字
216
+
217
+ byteBuffer(byteBufferPosition) = CType(byteData, Byte)
218
+
219
+ byteBufferPosition += 1
220
+
221
+ leadingByteData = 0
222
+
223
+ Loop
224
+
225
+ fs.Close()
226
+
227
+ End Using
228
+
229
+
230
+
231
+ ' result に、結果(List(Of String)型)が入っています。
232
+
233
+ End Sub
234
+
235
+
236
+
237
+ ' バイト値が SHIFT JIS の1バイト目とみなせればTrue、それ以外はFalseを返します。
238
+
239
+ Private Shared Function IsSJisLeadingByte(ByVal s As Byte) As Boolean
240
+
241
+ Return (&H81 <= s AndAlso s <= &H9F) OrElse (&HE0 <= s AndAlso s <= &HFC)
242
+
243
+ End Function
244
+
245
+ End Class
246
+
247
+ ```
248
+
249
+
250
+
251
+ ---
252
+
253
+
254
+
1
255
  こんにちは。
2
256
 
3
257
  私もCompactFrameworkを使用したことがないので、とんちんかんなことがありましたらご容赦ください。

3

修正

2016/01/29 04:42

投稿

hsk
hsk

スコア728

test CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  私もCompactFrameworkを使用したことがないので、とんちんかんなことがありましたらご容赦ください。
4
4
 
5
- 次のような箇所で改善できるかな、と思いました
5
+ 次のような箇所で改善できるかな、と思いました(「元のソース」の内容と重複したものもあります)
6
6
 
7
7
  - CSVデータの解析に[Microsoft.VisualBasic.FileIO.TextFieldParser](https://msdn.microsoft.com/ja-jp/library/microsoft.visualbasic.fileio.textfieldparser.aspx)クラスを使う
8
8
 

2

追記

2016/01/27 04:01

投稿

hsk
hsk

スコア728

test CHANGED
@@ -25,3 +25,11 @@
25
25
 
26
26
 
27
27
  ただ、限界がありそうでしょうから、dojikkoさんの仰られるように、ワーカースレッドとUIスレッドと分離して、操作感を確保することが一番有用だったりするかもしれません。
28
+
29
+
30
+
31
+ 追加で...
32
+
33
+ CsvToList関数に汎用性を持たせたい理由がないならば、CsvToList関数内でmodelデータを生成してそれを戻り値にすると、速度はいかがでしょう?
34
+
35
+ 現状のコードですと、CSVのフィールド数がどこかのレコードで万一不足していると、どのみち配列のOutOfRange例外が発生してしまいます。

1

提案追記

2016/01/27 03:58

投稿

hsk
hsk

スコア728

test CHANGED
@@ -21,3 +21,7 @@
21
21
 
22
22
 
23
23
  他にも思いつき次第、挙げてみます。
24
+
25
+
26
+
27
+ ただ、限界がありそうでしょうから、dojikkoさんの仰られるように、ワーカースレッドとUIスレッドと分離して、操作感を確保することが一番有用だったりするかもしれません。