概要

指定したURLのファイルをインターネットから1行ずつ取得しUTF8文字列をUNICODEでコンパイルした場合はUNICODE、マルチバイトでコンパイルした場合はSJISに変換してファイルに保存します。
本プログラムの使用方法はコマンドプロンプトを実行し、以下のように入力します。
以下の場合、私のホームページのUTF8文字列を含むutf8.htmlをファイルtest.htmlに保存します。
wgetutf8 http://yamatyuu.net/computer/html/charset/utf8.html test.html
インターネットからの読み込みにはWININETを使用しています。
WININETは1行ずつの読み込みに対応していないので、バッファリングと1行読み込みをサポートしたクラスを作成しています。

テスト環境

コンパイラ

Visual C++ 2008 Standard 32/64bit
Visual C++ 2013 Express 32/64bit

プロジェクトの作成

Win32プロジェクト Windowsコンソールアプリケーション

実行環境

Windows 8.1 Enterprise 64bit
Windows 7 EnterPrise Service Pack 1 64bit
Windows Vista Ultimate Service Pack 2 32bit
Windows XP Professional Service Pack 3 32bit

プログラムソースの概要

_tmain

UNICODE文字を標準エラー出力に正しく表示させるために_tsetlocale関数によりロケールを設定します。 InternetOpen APIによりインタネットハンドルを取得します。
APIが0を返した場合は、インタネットハンドルを取得できなかったので 標準エラー出力にエラーメッセージを表示しプログラムを終了させます。
_tfopen_sにより取得したデータを保存するためのファイルを書き込みでバイナリモードで開きファイルハンドルを取得します。
ファイルが開けなかった場合は、InternetCloseHandle APIによりインターネットハンドルを閉じて 標準エラー出力にエラーメッセージを表示しプログラムを終了させます。
webUTF8TextGet関数によりインタネット上のファイルを読み取り、ファイルに保存します。
InternetCloseHandle APIによりインターネットハンドルを閉じます。
fclose関数によりファイルハンドルを閉じます。

webUTF8TextGet

行単位での入力が可能なようにINETクラスを作成し、メンバー関数openで指定URLをオープンしハンドルを取得します。
オープンできなかった場合は、関数を終了します。
INETクラスgetsメンバー関数で1行を取得します。
MultiByteToWideChar APIによりUTF8文字列をUNICODE文字列に変換します。
マルチバイトでコンパイルされている場合は、WideCharToMultiByte APIによりUNICODE文字列をSJIS文字列に変換します。
_ftprintf関数でファイルに書き込みます。
読み込める行がなくなるまで、繰り返します。

INETクラス

inet.hで定義されています。
WININETは行単位の入力をサポートしていないので、クラス内でバッファリングを行い、 getsメンバー関数により行単位を要求された場合、バッファ内の行部分をコピーして返します。バッファが空になったらバッファサイズ分読み込みを行います。
¥nか¥rが行末であると解釈して処理を行います。

プログラムソース

wgetutf8.cpp

// インターネットより指定したurlを読み出しUTF8文字をUNICODE又はSJISに変換して指定したファイルへ保存します。
//	Visual C++ 2008/2013 Unicode/マルチバイト

#include 
#include 
#include 
#include 
#include 
#include "inet.h"

#pragma comment(lib,"wininet.lib")

//	指定したURLのUTF8テキストをUNICODEまたはSJISに変換して指定ファイルに保存する
void webUTF8TextGet(HINTERNET hInet, TCHAR* url, FILE* fp);


int _tmain(int argc,TCHAR** argv){
	HINTERNET hInet;
	_tsetlocale(LC_ALL, _TEXT(""));

	if (argc != 3){
		_tprintf(_TEXT("使用方法\nwgetutf8 [url] [保存ファイル名]\n"));
		return 1;
	}

	//インターネット(WinInet)開始
	hInet = InternetOpen(TEXT("wxz123"),
		INTERNET_OPEN_TYPE_PRECONFIG,	
		NULL, NULL, 0);
	if (hInet == NULL) {
		perror("オープンエラー\n");
		return 2;
	}
	FILE* fp;
#ifdef _UNICODE
	_tfopen_s(&fp, argv[2], _TEXT("w,ccs=UNICODE"));
#else
	_tfopen_s(&fp, argv[2], _TEXT("w"));
#endif
	webUTF8TextGet(hInet,argv[1],fp);
	fclose(fp);
	InternetCloseHandle(hInet);
	return 0;
}

//	指定したURLのUTF8テキストをUNICODEまたはSJISに変換して指定ファイルに保存する

void webUTF8TextGet(HINTERNET hInet, TCHAR* url, FILE* fp){
	HINTERNET h;
	INET inet(hInet);
	h = inet.open(url);
	char src[1024];
	TCHAR* dtc;
	while (inet.gets(src, sizeof(src))){
		WCHAR utf16[1024];
		//	UTF8をUNICODEに変換
		MultiByteToWideChar(CP_UTF8, 0, src, -1, utf16, sizeof(utf16) / sizeof(TCHAR));
#ifdef _UNICODE
		dtc = utf16;
#else
		char sjis[1024];
		//	UNICODEをSJISに変換
		WideCharToMultiByte(932, 0, utf16, -1, sjis, sizeof(sjis), NULL, NULL);
		dtc = sjis;
#endif
		_ftprintf(fp, _TEXT("%s\n"), dtc);
	}
	return;
}

inet.h

#ifndef INET_H

//	インターネットから1行ずつ読み取るクラス

#define INET_H 0x3000
#define INET_BUF_SIZE_DEF 65536

#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <wininet.h>
#include <assert.h>
#include <TCHAR.H>

class INET{
	HINTERNET hInet;
	HINTERNET hUrl;
	char*	buf;		//	読み取りバッファ(文字コード変換なし)
	unsigned		p;		//	バッファ内の位置
	DWORD	len;	//	バッファの有効データー数
	int wpos;
	int n;	//	バッファ内の読み出し可能先頭位置
	int INET_BUF_SIZE;
	bool new_mem_f;
public:
	UINT64	total_read;
	void init(HINTERNET h,void* bp,int sz){
		hInet=h;
		hUrl=0;
		p=len=0;
		INET_BUF_SIZE=sz;
		buf=(char*)bp;
		new_mem_f=false;
	}
	INET(){
		hInet=0;
		hUrl=0;
		p=len=0;
		INET_BUF_SIZE=0;
		buf=0;
		new_mem_f=false;
		total_read=0;
	}
	INET(HINTERNET h){
		hInet=h;
		hUrl=0;
		p=len=0;
		INET_BUF_SIZE=INET_BUF_SIZE_DEF;
		buf=new char[INET_BUF_SIZE+1];
		new_mem_f=true;
	}
	INET(HINTERNET h,int sz){
		hInet=h;
		hUrl=0;
		p=len=0;
		INET_BUF_SIZE=sz;
		buf=new char[INET_BUF_SIZE];
		new_mem_f=true;
	}
	HINTERNET open(TCHAR* url){
		wpos=0;
		n=0;
		return hUrl=InternetOpenUrl(hInet, url, NULL, 0, INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, 0);
	}
	int read(char* buf,int max){
		int len;
		InternetReadFile(hUrl, buf, max - 1, (LPDWORD)&len); 
		total_read += len;
		return len;
	}
	char* gets(char* b,int max){	// 1行分取得 改行コードを除去する
		int i=0;
		for(;;){
			if(p==0 || len==0){		//	バッファ内に有効データーがないのでサイトから読み取る
				len=read(buf,INET_BUF_SIZE);
			}
			if(len==0){
				return  0;
			}
			for(;p<len;p++){
				if(i==max-1){
					b[i]='\0';
					return b;
				}
				if(buf[p]=='\n' || buf[p]=='\r'){
					b[i]='\0';
					++p;
					return b;
				}else{
					b[i++]=buf[p];
				}
			}
			p=0;
		}

	}
	void close(void){
		if(hUrl)
			InternetCloseHandle(hUrl);
		hUrl=0;
	}
	~INET(){
		if(hUrl)
			InternetCloseHandle(hUrl);
		if(new_mem_f==true && buf)
			delete buf;
		INET_BUF_SIZE=0;
	}
};

#endif

ソースファイルと実行ファイルのダウンロード

ダウンロード wgetutf8.zip(61.3kByte)
ZIPファイルに含まれるファイル
wgetutf8.cpp
inet.h
wgetutf8.exe