tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルCSVを読み込みたい
記事No12113
投稿日: 2023/02/18(Sat) 14:08
投稿者初老のVB.NET開発者
いつも参考にさせていただいています。
早速ですが、質問です。
現在、VB.net2012でSQLServer2018とのデータベースシステムを
作っています。
そこで、CSVファイルからの読み込み機能を開発しているんですが
ファイルが読み込めず行き詰っています。
やりたいことは、CSVファイルをデータテーブルに一括に取り込み
たいということです
コードは、

Private Function GetCSVData(FilePATH As String ) As DataTable
  Dim cn As New OleDbConneection()
    Dim cmd As New OleDbCommand()
    Dim da As New OleDbDataAdapter()

    Dim CSVData As New DataTable

    Try
      Dim CNstr As String = "Provider=Microsoft.JET.OLEDB.4.0;"
      CNstr &= "Data Source=" & FilePath & ";"
      CNstr &= "Extended Properties=""Text;"
      CNstr &= "HDR=YES;"""
      cn.ConnectionString = CNstr
      cmd.Connection = cn
      Dim FileNM As String = Mid(FilePath, InStrRev(FilePath, "\")+1)
      cmd.CommandText = "SELECT * FROM [" & FileNM & "]"
      da.SelectCommand = cmd
      da.Fill(CSVData)←ここでエラーになります。
      Return CSVData
   Catch ex As Exception
      GerCSVData = Nothing
   Finaly
      cn.Dispose()
      cmd.Dispose()
      da.Dispose()
   End Try
です。[FileNM]には前処理でダイアログで選択したファイルパスが
入っています。
同じ方法でEXCELのデータを読み込むことには成功しているので
何が原因かわかりません。
どなたか、ご教授いただけると幸いです。
よろしくお願いします。

[ツリー表示へ]
タイトルRe: CSVを読み込みたい
記事No12114
投稿日: 2023/02/18(Sat) 16:45
投稿者魔界の仮面弁士
>       da.Fill(CSVData)←ここでエラーになります。
質問時には、正確なエラーメッセージを示しましょう。(^_^;

エラーになる要因として、Provider が読み込めないとか、
ファイルが読み込めないとか、権限不足であるなど、様々な要因がありえますが
エラー内容も示さずに判断を求めるのは、あまりにも酷というものです。

とりあえず、まず調べるべきは、
 1) そのアプリは、32bit プロセスで稼働しているのか、それとも 64bit プロセスなのか
 2) そもそも実行環境に、Jet 4.0 Provider がインストールされているのか
 3) CSV の型を明示指定するための Schema.ini ファイルの配置は行われているのか
 4) ファイルのパス指定に問題がある。
という点です。

実際のところ、4 のパス指定のミスという可能性が高いですが、
本当に Excel ファイルは読めているのだとすれば、思い当たるのは 3 です。
もしかしたら他の要因もあるかもしれませんが。


> 同じ方法でEXCELのデータを読み込むことには成功しているので
本当に「同じ」方法ですか? 実際は微妙に違うコードだったりしませんか?
CSV とでは、Extended Properties の指定方法が異なるはずで、
このコードのままでは読めないはずなのですが…。


> Dim FileNM As String = Mid(FilePath, InStrRev(FilePath, "\")+1)
素直に Path.GetFileName を使いましょう。VBA では無いのですから…。


> Dim CNstr As String = "Provider=Microsoft.JET.OLEDB.4.0;"
ACE 15/16 ではなく、Jet 4.0 で読み取るのですか?
https://www.microsoft.com/en-us/download/details.aspx?id=54920

下記の「Microsoft Jet データベース エンジン 4.0」の項には
『これらのアプリケーションについては、Jet から Microsoft Access データベース エンジンに
 移行することを計画する必要があります。』との記述があります。
https://learn.microsoft.com/ja-jp/sql/connect/connect-history?WT.mc_id=DT-MVP-8907&view=sql-server-ver16

Jet 4.0 の後継であった ACE 12 をベースとしている Access 2010 世代ですら
既にサポート期限が切れています。(再来月にサポート終了を迎える Access 2013 は ACE 13 世代)
Jet 4.0 は 32bit 専用の古い実装であり、64bit プロセスに対応できないという欠点もありますし、
どうせなら、今のうちに見直しておいた方が良いかもしれません。


> [FileNM]には前処理でダイアログで選択したファイルパスが
> 入っています。
FileNM に入っているのは、ファイルパスでは無いですよね。
ファイルパスが入っているのは FilePath では無いでしょうか。

それに、Extended Properties="Text;" モードの場合、
Data Source に指定するべきはディレクトリのパスであって、
ファイルのパスでもファイル名でもないはず…。

[ツリー表示へ]
タイトルRe^2: CSVを読み込みたい
記事No12115
投稿日: 2023/02/18(Sat) 21:35
投稿者初老のVB.NET開発者
魔界の仮面弁士さま、いつも投稿を拝見させていただいております。

> >       da.Fill(CSVData)←ここでエラーになります。
> 質問時には、正確なエラーメッセージを示しましょう。(^_^;
エラー内容を示していなくて申し訳ありませんでした。
ex。Messegeで内容を確認したところ、
「'(ファイルが置かれているパス)¥TEST.csv'は正しくありません。
 パス名に間違いがないことと、ファイルが置かれたサーバに接続して
 いることを確認してください。」
です。

> とりあえず、まず調べるべきは、
>  1) そのアプリは、32bit プロセスで稼働しているのか、それとも 64bit プロセスなのか
環境としては、32bitで稼働しています。

>  2) そもそも実行環境に、Jet 4.0 Provider がインストールされているのか
Jetはインストールされています。

>  3) CSV の型を明示指定するための Schema.ini ファイルの配置は行われているのか
すいません、これについては確認方法を検討がつかない状況です。

>  4) ファイルのパス指定に問題がある。
これは、ファイルをダイアログで選択しているので間違いはないと思っています。

> > 同じ方法でEXCELのデータを読み込むことには成功しているので
> 本当に「同じ」方法ですか? 実際は微妙に違うコードだったりしませんか?
> CSV とでは、Extended Properties の指定方法が異なるはずで、
> このコードのままでは読めないはずなのですが…。
最初、「Extended Properties」に設定していたのは「ACE.OLEDB12.0」でしたが
それでも読み込めなかったのでJETに変更してみました。

>
>
> > Dim FileNM As String = Mid(FilePath, InStrRev(FilePath, "\")+1)
> 素直に Path.GetFileName を使いましょう。VBA では無いのですから…。
すいません。.netに不慣れなもので「Path.GetFileName」が使えることを
知りませんでした。


> > [FileNM]には前処理でダイアログで選択したファイルパスが
> > 入っています。
> FileNM に入っているのは、ファイルパスでは無いですよね。
> ファイルパスが入っているのは FilePath では無いでしょうか。
すいません。表記を間違っていました。ここは「FilePath 」です。

>
> それに、Extended Properties="Text;" モードの場合、
> Data Source に指定するべきはディレクトリのパスであって、
> ファイルのパスでもファイル名でもないはず…。
もしかして、これって「Data Source」に指定するのは
「(ファイルが置かれているパス)¥TEST.csv」ではなく
「(ファイルが置かれているパス)¥」とするってことでしょうか?
だとすると「FilePath」には「(ファイルが置かれているパス)¥TEST.csv」までが
入っているので、間違いってことですね。

[ツリー表示へ]
タイトルRe^3: CSVを読み込みたい
記事No12116
投稿日: 2023/02/19(Sun) 00:31
投稿者魔界の仮面弁士
> >  3) CSV の型を明示指定するための Schema.ini ファイルの配置は行われているのか
> すいません、これについては確認方法を検討がつかない状況です。

たとえば、電話番号が数値に変換されてしまうとか、ハイフン区切りの数値が日付として
誤解されてしまうといった状況が発生する場合、列定義を Schema.ini ファイルとして記述します。

ini ファイルはメモ帳等で自作しても良いですが、これを作成するための画面も用意されています。

まず、"C:\Windows\SysWOW64\odbcad32.exe" を実行します。もしくは
[コントロール パネル]-[ODBC データ ソースのセットアップ (32 ビット)] からでも呼び出せます。

ユーザー/システム/ファイルいずれかの DNS タブで[追加]を押して、
"Microsoft Text Driver (*.txt; *.csv)" もしくは
"Microsoft Text-Treier (*.txt; *.csv)" のいずれかを選択します。

データソース名に任意の名前を付けてから、
[現在のフォルダーを使用する]を Off にして、
[フォルダーの選択]を押して、目標のフォルダーを選択します。

次に[オプション]ボタンを押して[書式の定義]ボタンを押し、
対象の csv が表示されたら、[推量] ボタンで列定義を読み取り、
データ型や列名に誤りがあれば修正します。

正しく設定されると、そのフォルダー内に "schema.ini" ファイルが生成されます。
この設定により、CSV だけでなく、セミコロン区切りやタブ区切り、固定長テキストなどにも対応できます。

"schema.ini" が無い場合は自動判断となりますが、その場合の既定値は、レジストリの
 HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Text
から読み込まれます(Jet 4.0 Provider の場合)。


> >  4) ファイルのパス指定に問題がある。
> これは、ファイルをダイアログで選択しているので間違いはないと思っています。
とは言ったものの、実際には間違っていたようですね。

> だとすると「FilePath」には「(ファイルが置かれているパス)¥TEST.csv」までが
> 入っているので、間違いってことですね。
JET Provider の Excel I-ISAM の場合、ブックがデータベース、シートがテーブルという扱いです。
(実際にはシートだけでなく、特定のセル範囲を指定して読み取ることもできますが)

それに対して Text I-ISAM の場合、フォルダーがデータベース、ファイルがテーブルという扱いです。

つまり、こうした文字列になるはずです。

「Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\txtFilesFolder\; Extended Properties="text;HDR=Yes;FMT=Fixed";」
「Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\tsvFilesFolder\; Extended Properties="text;HDR=No;FMT=TabDelimited";」


しかし最近の環境であれば、Jet Provider や ACE Provider に頼るよりも、
CSV 読み取り用のライブラリを NuGet した方が使い勝手が良いかも…。

https://www.blakepell.com/blog/csv-to-datatable-in-vb-net-or-c
https://tech-and-investment.com/csv1/
https://tech-and-investment.com/csv2/

[ツリー表示へ]
タイトルRe^4: CSVを読み込みたい
記事No12117
投稿日: 2023/02/19(Sun) 08:19
投稿者初老のVB.NET開発者
魔界の仮面弁士さん、ありがとうございます。

> JET Provider の Excel I-ISAM の場合、ブックがデータベース、シートがテーブルという扱いです。
> (実際にはシートだけでなく、特定のセル範囲を指定して読み取ることもできますが)
>
> それに対して Text I-ISAM の場合、フォルダーがデータベース、ファイルがテーブルという扱いです。
なるほど、やはりそういうことですか。
魔界の仮面弁士さんからご指南いただいてデータベースとファイルの関係性が理解できました。

> つまり、こうした文字列になるはずです。
> 「Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\txtFilesFolder\; Extended Properties="text;HDR=Yes;FMT=Fixed";」
> 「Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\tsvFilesFolder\; Extended Properties="text;HDR=No;FMT=TabDelimited";」
これって、「ACE」に対しても同じ書き方で大丈夫でしょうか?

とりあえず、今は自宅のPCで書き込んでいるので月曜日に出社してから試して
みようと思います。
Schema.iniについては検討してみようと思います。
外部ライブラリ導入についてはハードルが高そうです。
というのも、今私が行っている現場では簡単なフリーソフト導入時も個人の
判断ではできず情報管理部門の審査を経てからでないと導入できない決まりが
あります。それがライブラリとなると審査にかなりの手間が掛かると推察される
ので難しいそうです。
リンク先を見させていただきましたが、それほどインストール自体は
難しくないですし、便利なライブラリですし導入したいのですが。
会社で試してみて返信したいと思います。

[ツリー表示へ]
タイトルRe^5: CSVを読み込みたい
記事No12118
投稿日: 2023/02/20(Mon) 10:33
投稿者魔界の仮面弁士
> > 「Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\txtFilesFolder\; Extended Properties="text;HDR=Yes;FMT=Fixed";」
> > 「Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\tsvFilesFolder\; Extended Properties="text;HDR=No;FMT=TabDelimited";」
> これって、「ACE」に対しても同じ書き方で大丈夫でしょうか?

同じ書き方で大丈夫です。
Jet Provider から ACE Providre になっても、CSV 読み書きの仕様は基本的には変わらないです。

Jet 3.51 → Jet 4.0 あたりのタイミングで、指定可能な拡張子に制限が加えられもしましたが、
現行 OS にとってみれば、実質的な違いは無いはず。

なお、拡張子制限については下記を参照してください。
https://support.microsoft.com/ja-jp/topic/0c4042f2-9f1d-f762-d95c-41f19d21bcce

Text IISAM は、データベース操作によって「テキストファイルへの書き込み」が
行えてしまうという特性から、制限が加えられたという事情によるものです。


CSV 以外の面で、Jet から ACE に乗り換える場合に気にするとすれば、このあたりかな。

(1) 対応するデータベースバージョンの変化(*.mdb、*.accdb)
- Jet 3.51 … Version 1.0 / 1.1 / 2.0 / 3.0 / 3.5x への接続が可能
- Jet 4.0 … Version 1.0 / 1.1 / 2.0 / 3.0 / 3.5x / 4.0 への接続が可能
- ACE 12 … Version 1.0 / 1.1 / 2.0 / 3.0 / 3.5x / 4.0 / ACE への接続が可能
- ACE 14 … 3.x / 4.0 / ACE のみのサポート (1.0〜2.0 はサポートされない)
- ACE 15/16 … 4.0 / ACE のみのサポート (1.0〜3.x はサポートされない)

(2) *.xlsx 形式の Excel ファイルの読み書きをサポート(Extended Properties="Excel 12.0 Xml;")
※ *.xls 形式も引き続き扱えます。


> 外部ライブラリ導入についてはハードルが高そうです。
Jet 4.0 Provider や ACE Provider も、OS 標準機能では無いですけれどね。

.NET Framework の標準ライブラリだけという話なら、
 Microsoft.VisualBasic.FileIO.TextFieldParser クラス
を使う手もあります。ただしこのクラスは、セル内に連続した改行があった場合に、
空白行が失われるという制限があるため、個人的には他のパーサーを使った方が安全だと思います。

一方、「セル内改行」「セル内カンマ」などのパターンが無いのであれば、
 「改行」で行単位に分割 → 「,」で列単位に分割 → (必要なら)両端の「"」を除去
だけで済みます。


Imports System.IO
Imports System.Text
Imports System.Linq
Imports System.Text.RegularExpressions
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' http://jusyo.jp/csv/new.php
        Dim csvFile As String = "C:\CSV\47okinaw.csv"
        Dim csvData()() = ReadCsv(csvFile).ToArray()

        Dim tbl As New DataTable("沖縄")
        For Each column In csvData(0)
            tbl.Columns.Add(column, GetType(String))
        Next
        For Each columns In csvData.Skip(1)
            tbl.Rows.Add(columns.Cast(Of Object)().ToArray())
        Next
        tbl.AcceptChanges()

        Me.DataGridView1.DataSource = tbl
    End Sub

    Public Iterator Function ReadCsv(fileName As String) As IEnumerable(Of String())
        For Each line In File.ReadLines(fileName, Encoding.GetEncoding("Shift_JIS"))
            'Yield line.Split(","c).ToArray()
            Yield line.Split(","c).Select(AddressOf TrimQuote).ToArray()
        Next
    End Function

    '「"abc"」を「abc」に切り捨てる
    Private Function TrimQuote(s As String) As String
        'Return ("" & s).Trim(""""c)
        Return If(Regex.IsMatch(s & "", "^"".*"""), s.Substring(1, s.Length - 2), s)
    End Function
End Class

[ツリー表示へ]
タイトルRe^6: CSVを読み込みたい
記事No12119
投稿日: 2023/02/21(Tue) 06:14
投稿者初老のVB.NET開発者
魔界の仮面弁士さん、お世話になります。
昨日、会社にて「Data Source」のところを
「System.IO.Path.GetDirectoryName」で
指定したところ、無事読み込みに成功しました。
ありがとうございました。
ただ、読み込めたのはいいのですが
中身に一部全角が使用されているところが
あるのか、読み込んだ内容が文字化けを
起こしていて今度はその解消に手間取っています。

[ツリー表示へ]
タイトルRe^7: CSVを読み込みたい
記事No12120
投稿日: 2023/02/21(Tue) 10:47
投稿者魔界の仮面弁士
> 中身に一部全角が使用されているところがあるのか、

曖昧な記述は避け、掲示板を見ている第三者にも伝わるように
調べた範囲の情報を正確に提示いただけるようお願いします。

――すなわち
実際のファイルの文字コードは何であって、
実際に化けた位置にあったデータは、バイナリ表記でどういうデータで
実際に読み込んだ時には、どのような文字に化けてしまったのか
……といった情報を調査・提示すべきである、ということです。
それができるのは、実際のファイルをお持ちの元質問者殿だけなのですから。


なお、Jet Provider で扱えるのは、日本語環境だと Shift_JIS (CodePage 932) のファイルです。
ODBC Driver の設定画面で見た場合も、「ANSI」「OEM」しか選択肢に出てきません。
https://vb-user.net/junk/replySamples/2023.02.21.09.30/TextDriver.png

しかし ACE およびその世代の ODBC Drivder であれば任意のコードページがサポートされており、
「ANSI」「OEM」に加えて、「Unicode」「10進数」も指定できるようになっています。
この CharacterSet パラメーターは、接続文字列/schema.ini/レジストリのいずれかから指定できます。
https://vb-user.net/junk/replySamples/2023.02.21.09.30/CharcterSet.png
https://learn.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/initializing-the-text-data-source-driver?WT.mc_id=DT-MVP-8907

コードページの一覧については下記をご覧ください。
https://dobon.net/vb/dotnet/string/getencodings.html

[ツリー表示へ]
タイトルRe^8: CSVを読み込みたい
記事No12121
投稿日: 2023/02/21(Tue) 20:32
投稿者初老のVB.NET開発者
魔界の仮面弁士さん、返信ありがとうございます。
投稿に不備があり申し訳ありませんでした。
速報的に投稿してしまいました。

とりあえず、ステップインでプログラムを
追いかけたところどうやら、列見出しの表示の
ところで文字化けが起こります。
というのも、CSVの1行目を列見出しとするため
「HDR=Yes」で読み込んで列見出しを設定しています
そこで「条件No.」というフィールドの最後の「.(ドット)」
が「#」に化けてしまいます。
CSV自体はShift-JISを使っていたので文字化けしにくいと
思うのですが。現に1行目以外の全角文字は文字化けして
いないので。
なので、対策として行ったのは「HDR=No」にして
Fillで読み込んだ後、1行目の内容で列見出しを変更する
方法にしました。
これで無事意図したとおりに読み込むことができるように
なりました。

[ツリー表示へ]