この記事では、サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加する方法についてご説明します。
【動画】サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加する実際の動き
本題に入る前に、まずは次のツイートをご覧ください。
ディレクトリ配下全てのフォルダ名とファイル名をAccessのテーブルに追加するマクロを作成してみました😊
・フォルダ名とファイル名取得はコマンドプロンプトのdirコマンドで
・Accessのテーブル追加のためのデータ加工はマクロで
・Accessテーブルへの追加はDoCmd.TransferTextで#ExcelVBA#Access pic.twitter.com/UICpX6wgqc— まさ@Excel、VBA、マクロ(経験年数16年) (@masamasa9785) September 30, 2021
処理は大まかに次の3つを行っています。
- コマンドプロンプトを呼び出してdirコマンドでサブフォルダ含めて全てのフォルダ名とファイル名を取得してCSVに書き出す
- ①のCSVファイルに書き出されたフルパスを、パスとフォルダ名またはファイル名に分割してCSVファイルに書き出す
- ②のCSVファイルをDoCmd.TransferTextメソッドでAccessに追加する
サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加する方法
サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加するには次の二つを行います。
①Excelのマクロの作成
②Accessのエクスポート定義
②のエクスポート定義ですが、なぜエクスポート定義が必要なのかというと、Accessのテーブルに追加するのに取得したデータを加工した後、その加工データをAccessのテーブルに追加できるようにするのにエクスポート定義が必要になるからです。
エクスポート定義は本記事内のこちらで詳しく後述していますので、そちらをご覧ください。
Excelのマクロの作成の流れ
なお、書き出せるのは1行ずつです。(1度にまとめて複数行(または全行)書き出すことはできません)
コードの例
Excelのマクロのコード(例)
Sub test() Dim buf As String '一時的な値の格納先変数 Dim getPath As String 'サブフォルダ含めて全てのフォルダ名とファイル名を取得したいパス Dim cmdTxt As String 'コマンドプロンプトのコード用変数 Dim cnt As Long 'カウンタ(作業用) Dim shtNMCnt As Integer 'シート名用カウンタ Dim rPos_cnt As Long 'シートの行位置用カウンタ Dim ws As Worksheet 'Worksheet用変数 Dim fldrFileNMExptTxt As String 'フォルダ名とファイル名が出力されたファイル名 Dim SQL As String 'SQL文 Dim wshObj As WshShell 'WshShellオブジェクト Dim fso As FileSystemObject 'FileSystemObjectのインスタンス用変数 Dim st As ADODB.Stream 'バイナリ データまたはテキストのストリームのインスタンス用変数 Dim eRow As Long '一番下の行の位置 Dim saveF As String 'Accessのテーブルへの追加用に「項番*パス*フォルダ名(またはファイル名)*種類」の形式に編集・作成したデータ用CSVファイル Dim accessFileNM As String 'Accessのファイル名 Dim impTbl As String 'データを追加するAccessのテーブル名 Dim accApp As New Access.Application 'Accessアプリケーション参照用変数 'Excelの行数 Const rowMAXNum As Long = 1048576 'フォルダ名とファイル名を出力させるCSVファイル名を取得する fldrFileNMExptTxt = ActiveWorkbook.Path & "\" & "data.csv" 'Accessのテーブルへの追加用ファイル名を取得する saveF = ActiveWorkbook.Path & "\" & "save.csv" 'カウンタの初期化を設定 cnt = 1 'シートの行位置用カウンタの初期値を設定 rPos_cnt = 2 'シート名用カウンタの初期値を設定 shtNMCnt = 0 'サブフォルダ含めて全てのフォルダ名・ファイル名を取得したいパス getPath = "c:\work" 'バイナリ データまたはテキストのストリームのインスタンスを生成する Set st = New ADODB.Stream 'FileSystemObjectのインスタンスを生成する Set fso = New FileSystemObject 'WshShellオブジェクトからインスタンスを生成する Set wshObj = New WshShell If Right(getPath, 1) <> "\" Then '入力されたパスの末尾に「\」が付いていない場合に付ける getPath = getPath & "\" End If '実行するコマンド:dirコマンドでフルパスをCSVファイルに書き出す cmdTxt = "chcp 65001 | dir /b /s " & """" & getPath & """" & " > " & fldrFileNMExptTxt 'コマンドプロンプトで変数「cmdTxt」のコマンドを実行する Call wshObj.Run("%ComSpec% /c " & cmdTxt, 1, WaitOnReturn:=True) 'フォルダ名とファイル名貼り付け用シート有無のチェック For Each ws In Worksheets If ws.Name = "data" & CStr(shtNMCnt + 1) Then 'フォルダ名とファイル名貼り付け用シートが存在する場合 '確認ダイアログを非表示にする Application.DisplayAlerts = False 'フォルダ名とファイル名貼り付け用シートを選択する Sheets("data" & CStr(shtNMCnt + 1)).Select 'フォルダ名とファイル名貼り付け用シートを削除する ActiveWindow.SelectedSheets.Delete '確認ダイアログを表示可にする Application.DisplayAlerts = True shtNMCnt = shtNMCnt + 1 End If Next ws 'シート名用カウンタを0に初期化する shtNMCnt = 0 'フォルダ名・ファイル名を列挙するためのシートを新規作成する Worksheets.Add(After:=Worksheets(Worksheets.Count)) _ .Name = "data" & CStr(shtNMCnt + 1) '1行目に項目を設定する Sheets("data" & CStr(shtNMCnt + 1)).Range("A1").Value = "データ" With st .Charset = "UTF-8" '文字セットにUTF-8を設定する .Open 'streamを開く .LoadFromFile fldrFileNMExptTxt 'フォルダ名とファイル名が出力されたファイルから読み込む 'Streamの末尾まで繰り返す Do Until .EOS '取り出したテキストを変数「buf」に格納する buf = .ReadText(adReadLine) 'フルパスがフォルダなのかファイルなのかを判定する(True:ファイル/False:フォルダ) If fso.FileExists(buf) Then 'ファイルの場合 'フルパスから、Accessのテーブルへの追加用に「項番*パス*フォルダ名(またはファイル名)」の形式のデータを編集・作成してA列に設定する '※Accessのテーブルへの追加データの区切り文字として「*」を採用(ファイルやフォルダー名に使用できない文字として「*」を採用) Sheets("data" & CStr(shtNMCnt + 1)).Cells(rPos_cnt, 1).Value = cnt & "*" & _ Left(buf, InStrRev(buf, "\")) & "*" & _ WorksheetFunction.Replace(buf, 1, InStrRev(buf, "\"), "") & "*" & _ "file" Else 'フォルダの場合 'フルパスから、Accessのテーブルへの追加データ用に「項番*パス*フォルダ名(またはファイル名)」の形式のデータを編集・作成してA列に設定する '※Accessのテーブルへの追加データの区切り文字として「*」を採用(ファイルやフォルダー名に使用できない文字として「*」を採用) Sheets("data" & CStr(shtNMCnt + 1)).Cells(rPos_cnt, 1).Value = cnt & "*" & _ Left(buf, InStrRev(buf, "\")) & "*" & _ WorksheetFunction.Replace(buf, 1, InStrRev(buf, "\"), "") & "*" & _ "fldr" End If rPos_cnt = rPos_cnt + 1 'Excelの行数を超える場合 If (rPos_cnt Mod rowMAXNum) = 0 Then shtNMCnt = shtNMCnt + 1 '(Excelの行数を超えるので)フォルダ名・ファイル名を列挙するためのシートを新規作成する Worksheets.Add(After:=Worksheets(Worksheets.Count)) _ .Name = "data" & CStr(shtNMCnt + 1) '1行目に項目を設定する Sheets("data" & CStr(shtNMCnt + 1)).Range("A1").Value = "データ" 'シートの行位置用カウンタの初期値を設定(シートを追加したのでまた2行目からカウントする) rPos_cnt = 1 End If cnt = cnt + 1 DoEvents Loop 'Streamの末尾まで処理が終わったので、streamを閉じる .Close 'ADODB.Streamを開く .Open For cnt = 0 To shtNMCnt '一番下の行の位置を取得する eRow = Sheets("data" & CStr(cnt + 1)).Cells(1, 1).End(xlDown).Row 'それ以降(A列の値がある間はループする) For rPos_cnt = 1 To eRow .WriteText Sheets("data" & CStr(cnt + 1)).Cells(rPos_cnt, 1) '行の最後で改行コードを追加する .WriteText vbCrLf Next Next 'ADODB.Streamに保管されている内容を、ファイルに保存する .SaveToFile saveF, 2 'ADODB.Streamを閉じる .Close End With 'カレントディレクトリのAccessファイル名を取得 accessFileNM = ActiveWorkbook.Path & "\" & "0078.mdb" 'CSVファイルにデータをエクスポートするAccessのテーブル名を取得 impTbl = "tbl_folderfile_list" 'Accessファイルを開く Set accApp = GetObject(accessFileNM) 'Accessを非表示にする accApp.Visible = False 'Accessの確認ダイアログを非表示にする accApp.DoCmd.SetWarnings False 'テーブルデータを削除する SQL = "DELETE FROM " & impTbl 'SQL文を実行する accApp.DoCmd.RunSQL SQL 'Accessの確認ダイアログを表示可にする accApp.DoCmd.SetWarnings True 'CSVファイルのデータをテーブルにインポートする accApp.DoCmd.TransferText acImportDelim, "T定義", impTbl, saveF, True '後処理 'フォルダ名とファイル名が出力されたファイルを削除する Call fso.DeleteFile(fldrFileNMExptTxt, True) 'Accessのテーブルへの追加用ファイルを削除する Call fso.DeleteFile(saveF, True) 'シート名用カウンタの初期値を設定 shtNMCnt = 0 'フォルダ名とファイル名貼り付け用シート有無のチェック For Each ws In Worksheets If ws.Name = "data" & CStr(shtNMCnt + 1) Then 'フォルダ名とファイル名貼り付け用シートが存在する場合 '確認ダイアログを非表示にする Application.DisplayAlerts = False 'フォルダ名とファイル名貼り付け用シートを選択する Sheets("data" & CStr(shtNMCnt + 1)).Select 'フォルダ名とファイル名貼り付け用シートを削除する ActiveWindow.SelectedSheets.Delete '確認ダイアログを表示可にする Application.DisplayAlerts = True shtNMCnt = shtNMCnt + 1 End If Next ws '後処理 Set st = Nothing Set fso = Nothing Set accApp = Nothing End Sub
コードの解説
注目すべきコード①
最初に見て頂きたいのは59行目から62行目です。
'実行するコマンド:dirコマンドでフルパスをCSVファイルに書き出す cmdTxt = "chcp 65001 | dir /b /s " & """" & getPath & """" & " > " & fldrFileNMExptTxt 'コマンドプロンプトで変数「cmdTxt」のコマンドを実行する Call wshObj.Run("%ComSpec% /c " & cmdTxt, 1, WaitOnReturn:=True)
59行目でコマンドプロンプトでdirコマンドを実行するためのコマンド文を変数に格納し、そのコマンド文を62行目でRunメソッドの引数に設定してコマンドプロンプトでdirコマンドを実行しています。
なぜわざわざコマンドプロンプトを使っているのか(呼び出しているのか)というと、処理の高速化を図るためです。
大量のフォルダやファイルが存在する場合に、マクロだけでやろうとすると時間がかかりすぎるために高速化が実現できるコマンドプロンプトを使っています。
(※絶対にコマンドプロンプトを使わなければいけないというわけではありませんが、今回は手軽に使うことができるコマンドプロンプトを採用しました)
例えば、私のパソコンのCドライブ配下にはサブフォルダ含めて全てのフォルダとファイルの数はファイル数が110万超、フォルダー数が250万近くありますが、これほどの数をExcelマクロだけでシートに書き出そうとすると何時間もかかってしまいます。
これだけの大量にあるフォルダとファイルを取得してシートに書き出したい場合に、マクロだけで行うのは処理時間を考えると現実的ではないです。
一方、コマンドプロンプトを呼び出してdirコマンドを使い(Cドライブ配下の)、ファイル名とサブディレクトリ名を一覧出力すると(私のパソコンでは)20分弱で終わりました。(完了するまでの時間はPCのスペックに左右されますが)
話を戻しますが、59行目のコードではどんなコマンド文が呼び出されるのか分かりにくいのでサンプルをお見せします。
chcp 65001 | dir /b /s "C:\" > C:\work\data.csv
このコマンド文は1行ですが、実は2つのコマンドを1行で実行しています。
2つのコマンドは次の通りです。
①chcp 65001
②dir /b /s “C:\” > C:\work\data.csv
- ①のコマンドは、文字コードをUTF-8に設定するコマンドで、文字化けしないように文字コードをUTF-8に設定しています。
(文字コードをUTF-8に設定すると文字化けしない) - ②のコマンドは、dirコマンドを実行してファイル「data.csv」にディレクトリにあるファイルとサブディレクトリの一覧出力しています。
以上、上記のコマンドが実行されると、フォルダ名とファイル名が出力された「data.csv」というファイルが出力されます。
この「data.csv」をExcelマクロが読み込んでシートにフォルダ名とファイル名をセルに書き出していきます。
ちなみに、フォルダ名とファイル名を全てセルに書き出したら、必要がなくなるので222行目で削除します。
'フォルダ名とファイル名が出力されたファイルを削除する Call fso.DeleteFile(fldrFileNMExptTxt, True)
注目すべきコード②
次に見て頂きたいのは99行目から134行目です。
With st .Charset = "UTF-8" '文字セットにUTF-8を設定する .Open 'streamを開く .LoadFromFile fldrFileNMExptTxt 'フォルダ名とファイル名が出力されたファイルから読み込む 'Streamの末尾まで繰り返す Do Until .EOS '取り出したテキストを変数「buf」に格納する buf = .ReadText(adReadLine) 'フルパスがフォルダなのかファイルなのかを判定する(True:ファイル/False:フォルダ) If fso.FileExists(buf) Then 'ファイルの場合 'フルパスから、Accessのテーブルへの追加用に「項番*パス*フォルダ名(またはファイル名)*種類」の形式のデータを編集・作成してA列に設定する '※Accessのテーブルへの追加用の区切り文字として「*」を採用(ファイルやフォルダー名に使用できない文字として「*」を採用) Sheets("data" & CStr(shtNMCnt + 1)).Cells(rPos_cnt, 1).Value = cnt & "*" & _ Left(buf, InStrRev(buf, "\")) & "*" & _ WorksheetFunction.Replace(buf, 1, InStrRev(buf, "\"), "") & "*" & _ "file" Else 'フォルダの場合 'フルパスから、Accessのテーブルへの追加用に「項番*パス*フォルダ名(またはファイル名)*種類」の形式のデータを編集・作成してA列に設定する '※Accessのテーブルへの追加用の区切り文字として「*」を採用(ファイルやフォルダー名に使用できない文字として「*」を採用) Sheets("data" & CStr(shtNMCnt + 1)).Cells(rPos_cnt, 1).Value = cnt & "*" & _ Left(buf, InStrRev(buf, "\")) & "*" & _ WorksheetFunction.Replace(buf, 1, InStrRev(buf, "\"), "") & "*" & _ "fldr" End If
101行目で、文字コードをUTF-8に設定してフォルダ名とファイル名が出力された「data.csv」をExcelマクロが読み込むためにCharsetプロパティに「UTF-8」の文字列を設定しています。
次に102行目でOpenメソッドを実行し、103行目のLoadFromFile メソッドの引数に「data.csv」を設定して「data.csv」を読み込みます。
106行目のDoループで、読み込んだ「data.csv」の行数分処理を繰り返します。
109行目では、1行取り出して変数「buf」に格納しています。この1行はフルパスになります。
118行目または129行目で、取り出した1行(フルパス)からAccessのテーブルへの追加用に「項番*パス*フォルダ名(またはファイル名)*種類」の形式のデータに編集・作成してA列に設定します。
なお、フォルダの場合は118行目で「項番*パス*フォルダ名*fldr」の形式のデータを、ファイルの場合は129行目で「項番*パス*ファイル名*file」の形式のデータに編集・作成してA列に設定しています。
(fldrはフォルダ、fileはファイルのことを指します。フォルダなのかファイルなのかがすぐ分かるように設定しています。)
ちなみに、Accessのテーブルへの追加用の区切り文字として「*」を使っています。
Accessのテーブルへの追加実行時に想定外に文字列を区切られないよう、ファイルやフォルダー名に使用できない文字として「*」を採用しました。
(「,」や「スペース文字」などはフォルダ名やファイル名に使われていることがあるため使わない)
注目すべきコード③
次に見て頂きたいのは139行目から145行目です。
'Excelの行数を超える場合 If (rPos_cnt Mod rowMAXNum) = 0 Then shtNMCnt = shtNMCnt + 1 '(Excelの行数を超えるので)フォルダ名・ファイル名を列挙するためのシートを新規作成する Worksheets.Add(After:=Worksheets(Worksheets.Count)) _ .Name = "data" & CStr(shtNMCnt + 1)
フォルダとファイルの数がExcelの最大行数を超える場合は、新たにシートを追加します。
最大行数を超えるかを139行目で判定し、もし超える場合は144行目で新たにシートを作成します。
注目すべきコード④
次に見て頂きたいのは40行目です。
'サブフォルダ含めて全てのフォルダ名・ファイル名を取得したいパス getPath = "c:\work"
40行目で、サブフォルダ含めて全てのフォルダ名とファイル名を取得するパスを指定しています。
注目すべきコード⑤
次に見て頂きたいのは217行目です。
'CSVファイルのデータをテーブルにインポートする accApp.DoCmd.TransferText acImportDelim, "T定義", impTbl, saveF, True
217行目でDoCmd.TransferTextメソッドを実行し、CSVファイルのデータをAccessのテーブルに追加しています。
- 【第1引数:変換の種類】CSVをインポートする場合に、acImportDelimを指定
- 【第2引数:インポート定義名】インポート定義名を指定(※インポート定義がなければ指定しない)
- 【第3引数:インポート先テーブル名】インポート先のテーブル名を指定
- 【第4引数:インポートするファイル名】インポートするファイル名を指定
- 【第5引数:テキストファイルの1行目をフィールド名とするか】テキストファイルの1行目をフィールド名とするか指定
⇒True:指定する、False指定しない
注目すべきコード⑥
次に見て頂きたいのは199行目です。
'Accessファイルを開く Set accApp = GetObject(accessFileNM)
199行目のGetObject関数の引数にAccessファイルを指定して実行するとインスタンスが生成され、DoCmd.TransferTextメソッドを含めてAccessのメソッドやプロパティ全てが使用可能になります。
※変数「accessFileNM」はAccessファイル名が格納された変数
エクスポート定義について
フォルダ名とファイル名を出力させるCSVファイルのデータをAccessのテーブルに追加するにはエクスポート定義の作成が必要です。
なぜエクスポート定義が必要なのかというと、マクロで加工した「項番*パス*フォルダ名(またはファイル名)*種類」の形式のデータを「*」区切りでAccessのテーブルに追加したいためです。
「*」区切りでAccessのテーブルに追加するにはエクスポート定義を作成する必要があります。
「*」区切りでAccessのテーブルに追加できるようエクスポート定義を作成しておき、マクロを実行することでAccessのテーブルに追加することができます。
エクスポート定義を作成しないと、「項番*パス*フォルダ名(またはファイル名)*種類」の形式のデータを「*」で区切れず正しくAccessのテーブルに追加できません。
なので、これからご説明する手順に従いエクスポート定義を行います。
エクスポート定義の作成の例
エクスポート定義の作成方法は次の通りです。
①テーブルのエクスポートで「テキストファイル」をクリック
データを追加するテーブルを右クリックし、「エクスポート」→「テキストファイル」をクリックします。
②「データのエクスポート先の選択」でファイル名を入力
「データのエクスポート先の選択ウィザード」でファイル名を入力し、OKボタンをクリックします。
※本記事ではファイル名の指定以外は何も選択しないで説明を続けます。
③「テキストエクスポートウィザード」の「設定」ボタンをクリック
「テキストエクスポートウィザード」の「設定」ボタンをクリックします。
④「フィールド区切り記号」の入力と「コードページ」の選択後に保存をクリック
「フィールド区切り記号」に「*」(アスタリスク)を入力し、「コードページ」に「Unicode (UTF-8)」を選択したら保存ボタンをクリックします。
「フィールド区切り記号」に「*」を入力することで、「項番*パス*フォルダ名(またはファイル名)*種類」の形式のデータを「*」で区切ることができます。
また、Accessのテーブルに追加するデータがUTF-8形式なので、「コードページ」に「Unicode (UTF-8)」を選択します。(選択しないと文字化けします)
⑤「インポート/エクスポート定義の保存ダイアログ」で定義名を入力
「インポート/エクスポート定義の保存ダイアログ」で定義名を入力し、OKボタンをクリックします。
定義名は任意です。ですが、マクロのDoCmd.TransferTextメソッドの第2引数(コードの例では「T定義」)と同じにする必要があります。
'CSVファイルのデータをテーブルにインポートする accApp.DoCmd.TransferText acImportDelim, "T定義", impTbl, saveF, True
同じでないとマクロ実行時にエラーになります。(定義名見つからないので怒られます)
⑥OKボタンをクリック
OKボタンをクリックします。
⑦「完了」ボタンをクリック
「完了」ボタンをクリックします。
⑧閉じるボタンをクリック
閉じるボタンをクリックします。
エクスポート定義の作成は以上です。
エクスポート定義ファイルとエクスポート定義の確認
①エクスポート定義ファイル
エクスポート定義ファイルは画像のテキストファイルです。
②エクスポート定義
エクスポート定義は「エクスポート定義ウィザード」画面で「定義」ボタンをクリックすると、「インポート/エクスポート定義」ダイアログが表示されます。
先ほど作成したエクスポート定義名が表示されていることを確認できればOKです。
テーブル定義
今回ご紹介したAccessのテーブル(例)の定義は次の通りです。
サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加した結果
本マクロを実行すると、サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加されたことが確認できました。
【注意】参照設定が必要です
一つ注意点があるのですが、先ほどのコードを動かすには参照設定が必要です。
参照設定の一覧(下の画像を参考)から次の項目(ライブラリ)にチェックを付けて「OK」ボタンをクリックします。
- Microsoft ActiveX Data Objects 2.8 Library(msado28.tlb)
- Windows Script Host Object Model(wshom.ocx)
- Microsoft Access 15.0 Object Library(MSACC.OLB)
なぜ必要かというと、先ほどのコードの12行目と13行目の「WshShell」「FileSystemObject」というオブジェクトが「wshom.ocx」というファイルを、14行目の「ADODB.Stream」というオブジェクトが「msado28.tlb」というファイルを、19行目の「Access.Application」というオブジェクトが「MSACC.OLB」というファイルを参照するからです。
Dim wshObj As WshShell 'WshShellオブジェクト Dim fso As FileSystemObject 'FileSystemObjectのインスタンス用変数
Dim st As ADODB.Stream 'バイナリ データまたはテキストのストリームのインスタンス用変数
Dim accApp As New Access.Application 'Accessアプリケーション参照用変数
この参照設定をしないと下の画像のエラーが出ますので必ず行う必要があります。
ここでは「msado28.tlb」「wshom.ocx」「MSACC.OLB」それぞれが何者かについては記事の本題から逸れてしまうので詳細は割愛しますが、マクロで次のオブジェクトを使う場合は参照設定しないと動かない、程度に思って頂ければと思います。
- WshShell
- FileSystemObject
- ADODB.Stream
- Access.Application
最後に
本記事では、サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加する方法についてご説明しました。
サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加する処理の流れは次の通りです。
- コマンドプロンプトを呼び出してdirコマンドでサブフォルダ含めて全てのフォルダ名とファイル名を取得してCSVに書き出す
- ①のCSVファイルに書き出されたフルパスを、パスとフォルダ名またはファイル名に分割してCSVファイルに書き出す
- ②のCSVファイルをDoCmd.TransferTextメソッドでAccessに追加する
サブフォルダ含めて全てのフォルダ名とファイル名を取得してAccessのテーブルに追加したい場合は参考にしてみてくださいね。
プログラミングのスキルを習得するなら
プログラミングのスキルを習得したい、今のスキルをもっと高めたい、そう考えているなら「プログラミングスクール」がおすすめです。
プログラミングのスキルの基礎を身につけるなら「TechAcademy」で1週間の無料体験があるので、これで「プログラミングの基礎」を学ぶのにおすすめですよ。