txtファイルの圧縮

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ares

txtファイルの圧縮

#1

投稿記事 by ares » 14年前

コード:

#include <stdio.h>
#include <stdlib.h>

void func(FILE *fp1, FILE *fp2)
{
	int c1, c2, l = 0;

	for(c1 = c2 = fgetc(fp2); c1 != EOF; c2 = fgetc(fp2)){
		if(c1 != c2){
		fprintf(fp1, "%c%d", c1, l);
		l = 1;
		c1 = c2;
		}
	else l++;
	}
}

int main(void)
{
	FILE *fp1 = fopen("before.txt", "w"), *fp2 = fopen("after.txt", "r");

	if(!fp1 || !fp2) exit(EXIT_FAILURE);
	func(fp1, fp2);
	fclose(fp1);
	fclose(fp2);
	return 0;
}
もともと存在するtxtファイルのbefore.txtをランレングス圧縮するプログラムを作りたいのですが
ただ、before.txtには数字も含まれています

へにっくす

Re: txtファイルの圧縮

#2

投稿記事 by へにっくす » 14年前

ares さんが書きました:

コード:

#include <stdio.h>
#include <stdlib.h>

void func(FILE *fp1, FILE *fp2)
{
	int c1, c2, l = 0;

	for(c1 = c2 = fgetc(fp2); c1 != EOF; c2 = fgetc(fp2)){
		if(c1 != c2){
			fprintf(fp1, "%c%d", c1, l);
			l = 1;
			c1 = c2;
		}
		else l++;
	}
}

int main(void)
{
	FILE *fp1 = fopen("before.txt", "w"), *fp2 = fopen("after.txt", "r");

	if(!fp1 || !fp2) exit(EXIT_FAILURE);
	func(fp1, fp2);
	fclose(fp1);
	fclose(fp2);
	return 0;
}
もともと存在するtxtファイルのbefore.txtをランレングス圧縮するプログラムを作りたいのですが
ただ、before.txtには数字も含まれています
何がしたいのでしょう?
掲示しているソースをみる限り、
after.txtを読み込んでbefore.txtに書き込む処理のように見えますが。
before.txtは結果なので、数字も含まれるのは当然な気がしますが、、

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: txtファイルの圧縮

#3

投稿記事 by softya(ソフト屋) » 14年前

仕様レベルの質問でしょうか?
長さを表すのに数値文字を使っているので続けて数字の文字があると切れ目がわからない問題があると思います。
そこを如何に解決するかお考えでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ares

Re: txtファイルの圧縮

#4

投稿記事 by ares » 14年前

返信をいただいた方の意見を参考に作りなおしてみたのですが
http://gihyo.jp/book/2010/978-4-7741-4307-1/support
でダウンロードできるtxtファイルを圧縮してみたところファイルが大きくなってしまいました。
問題点などがあればっぜひお願いします。

コード:

#include <stdio.h>

#define ABCD 0x1b

void encode(FILE *fp1, FILE *fp2)
{
    int ch, tmp, count = ' ';

    tmp = EOF;

    while ( EOF != (ch = fgetc(fp1)) ) {
        if ('~' == count)
            tmp = EOF;
        if (tmp == ch)
            count++;
        else if (' ' == count)
            fputc(ch, fp2);
        else {
            fputc(ABCD,  fp2);
            fputc(count, fp2);
            fputc(ch,    fp2);
            count = ' ';
        }
        tmp = ch;
    }

    if (' ' != count) {
        fputc(ABCD,  fp2);
        fputc(count, fp2);
    }
}

int main(void)
{
    FILE *fp1, *fp2;
	
    fp1 = fopen("before.txt", "r");
	fp2 = fopen("after.txt", "w");

    if (NULL == fp1 || NULL == fp2) {
        puts("error");
        return 0;
    }

    encode(fp1, fp2);

    fclose(fp1);
    fclose(fp2);

    return 0;
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: txtファイルの圧縮

#5

投稿記事 by softya(ソフト屋) » 14年前

テキストモードでのランレングス圧縮ですから元より大きくなる可能性が高いと思います。
例えバイナリでも工夫しないと元より大きくなる可能性が高いのがランレングスですので。

以前の質問にお応えいただいていませんが、今の仕様を説明していただいても良いですか?
その方が早いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ares

Re: txtファイルの圧縮

#6

投稿記事 by ares » 14年前

>>softya(ソフト屋)さん
こういうことでよろしいですか?今回は前の投稿であげたURLからダウンロードできるデータを半分以下のサイズに圧縮するプログラムをつくりなさいという課題で自分は圧縮に関して無知に等しかったので基本的なランレングス圧縮を採用したのですがバイナリにしなければ難しいですかね?

コード:

void encode(FILE *fp1, FILE *fp2)
{
    int ch, tmp, count = ' ';

    tmp = EOF;

    while ( EOF != (ch = fgetc(fp1)) ) {
        if ('~' == count) /* 繰り返し数が限界の場合の処理 */
            tmp = EOF;
        if (tmp == ch) /* 直前の文字と同じなら繰り返しとする */
            count++;
        else if (' ' == count)/* 1文字だけの出力 */
            fputc(ch, fp2);
        else {
            fputc(ABCD,  fp2);
            fputc(count, fp2);
            fputc(ch,    fp2);/* 繰り返しの処理はABCDを出力し、繰り返し数を出力する。新しく読んだ文字を出力  */
            count = ' ';
        }
        tmp = ch;
    }

    if (' ' != count) {
        fputc(ABCD,  fp2);
        fputc(count, fp2);/* 繰り返しの処理が残っているとき */
    }
}


アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: txtファイルの圧縮

#7

投稿記事 by softya(ソフト屋) » 14年前

while抜けで残っていた時の処理で文字が出力されていません。
[ABCD][count][ch]でセットですよね。

あと、これだと2文字以上連続した時に3文字分を消費しますので元より確実に大きくなるでしょう。
4文字以上連続しない限り圧縮コードを出さないように工夫すべきです。
※ 元よりは大きくなりませんが小さくなる可能性も低いと多いと思います。

このアルゴリズムのままバイナリにしても3バイトが2バイトになるぐらいで大きな効果は期待できません。
半分のサイズまで圧縮するならランレングスよりも辞書法やあるいはデータの特性に注目した圧縮方法を採用すべきでしょう。
それと、URLからダウンロードできるデータの文字コードはshift-jisでは無いみたいですが処理はshift-jis前提なのも問題でしょう。バイナリとして処理したほうが良いのでは?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

“C言語何でも質問掲示板” へ戻る