Création d'un fichier d'une taille fixe

foufou20071987 Messages postés 13 Date d'inscription mercredi 18 mai 2011 Statut Membre Dernière intervention 9 novembre 2013 - Modifié par BunoCS le 29/09/2013 à 10:19
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 - 29 sept. 2013 à 11:19
Bonsoir,voila mon code de création d'un fichier d'une taille fixe rempli par des caractères aléatoirement .Mon problème c'est qu'il dépasse la taille demandé par quelque octet.Pouvez vous m'aider a fixer la taille?Merci d'avance
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cénérateurfichier;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
public class fichier {
 
    public static void main(String[] args) {
 
        System.out.println("Entrer le nom du fichier");
        String nomfichier;
        nomfichier =  lireString();
        System.out.println("Entrer la taille du fichier en Mo");
int taille = lireInt();
 java.io.File fichier = new java.io.File(nomfichier);       
try 
{ 
fichier.createNewFile(); 
} 
catch (IOException e) 
{ 
System.out.println("Impossible de créer le fichier"); 
} 
String random , s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ";
try {
    FileWriter fw= new FileWriter(nomfichier,true);
    while(fichier.length()<=(taille*1024*1024))
    {
        random="";
        for(int j=0;j<99;j++)   
          {
            int i = (int)Math.floor(Math.random() * 63);
            random+=s.charAt(i);
            fw.write(random);
          }
    }
    fw.close();
    System.out.println(fichier.length());
} catch(IOException e) {
    System.out.println("Impossible d'écrire dans le fichier");
}
 }    
 public static String lireString(){
String ligne_lue=null; 
try{ 
InputStreamReader lecteur=new InputStreamReader(System.in); 
BufferedReader entree=new BufferedReader(lecteur); 
ligne_lue=entree.readLine(); 
} 
catch(IOException err){ 
System.exit(0); 
} 
return ligne_lue; 
} 
    public static int lireInt(){
int x=0; 
try{ 
String ligne_lue=lireString(); 
x=Integer.parseInt(ligne_lue); 
} 
catch(NumberFormatException err){ 
System.out.println("***Erreur de données Entier attendu***"); 
System.exit(0); 
} 
return x; 
} 
 
}


--

1 réponse

KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 127
Modifié par KX le 29/09/2013 à 12:15
1) Il y a des conventions de nommage et il faut les respecter !
Ne mets pas d'accents dans ton code Java (sauf dans les commentaires bien sûur), ni dans les noms de variable, ni dans les noms de classe, et surtout pas dans les noms de package !
Les noms de classe doivent commencer par une majuscule. Cela permet d'éviter de faire des confusions avec les variable. Par exemple quand tu écris "fichier.createNewFile()", le nom "fichier" se rapporte à la variable "File fichier", mais cela aurait très bien pu être aussi une méthode static de ta classe "fichier". En mettant une majuscule au nom de la classe "Fichier" ça désambiguïses le code...
De même les noms de variables ne devraient pas contenir de tirets comme tu le fais pour "ligne_lue", en respectant les conventions il faudrait nommer ta variable "ligneLue"

2) C'est bien de mettre les balises de code sur le forum, mais l'idéal serait quand même que le code que tu écris soit correctement indenté, ne serait-ce que pour toi qui le rédige !

3) Pour tes lectures du clavier, je te conseilles d'utiliser la classe Scanner, elle est plus simple à utiliser. De plus ne masque pas les exceptions, il faut conserver la trace des erreurs.

private static final Scanner clavier = new Scanner(System.in);

public static String lireString()
{
    try
    {
        return clavier.nextLine();
    }
    catch (Exception e)
    {
        throw new RuntimeException("Erreur de données.", e);
    }
}

public static int lireInt()
{
    try
    {
        int n = clavier.nextInt();
        clavier.nextLine();
        return n;
    }
    catch (Exception e)
    {
        throw new RuntimeException("Erreur de données. Entier attendu.", e);
    }
}


4) De même que tu as séparé tes méthodes lireString et lireInt du reste de ton main, il faudrait aussi mettre ta méthode de création de fichier dans une méthode indépendante. Il serait également intéressant de faire la partie "aléatoire" également à part.

public static final String VALUES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ";

private static final Random random = new Random();

public static char getRandomChar()
{
    return VALUES.charAt(random.nextInt(VALUES.length()));
}
    
public static void createRandomFile(String nameFile, int sizeFile) throws IOException
{
    // ...
}

public static void main(String[] args)
{
    System.out.println("Entrer le nom du fichier");
    String nomFichier = lireString();
    
    System.out.println("Entrer la taille du fichier en Mio");
    int taille = lireInt();
    
    try
    {
        createRandomFile(nomFichier, taille);
    }
    catch (Exception e)
    {
        throw new RuntimeException("Erreur lors de la création du fichier.", e);
    }
}


5) Pour en venir au coeur même de ton problème (même si tous les à côtés comptent autant), il faut déjà oublier ton test fichier.length(), cela n'a pas de sens tant que ton fichier n'est pas terminé, en plus comme tu gères toi même la boucle, tu peux facilement compter quelle est la taille du fichier au fur et à mesure que tu le remplis.

Ensuite, tu utilises un FileWriter avec un append true, c'est à dire que tu considères que tu peux ajouter des données à la fin du fichier existant. Or tu sais que le fichier n'existe pas puisque le but est de le créer !

Et il y a surtout cette horreur de boucle for (int j=0; j<99; j++).
Je ne comprends pas ce qu'elle vient faire là, parce que tu vas rajouter des caractères par blocs de 99, en espérant que ce soit un multiple de 1024*1024, ce qui n'a évidemment aucune chance d'arriver et c'est pour ça que tu débordes dans ta taille.
Exemple pour 1 Mo, tu veux 1048576 octets, mais avec ta boucle tu vas faire 10592 blocs de 99 octets, ce qui fait un total 1048608, soit 32 octets en trop...

Pour que cela tombe juste il faudrait utiliser des blocs qui soient des portions de 1024*1024, par exemple avec 8192 blocs de 128 octets. Et là tu es sûr que tu tombes sur un Mio entier.

Par contre évites les opérations de type String += String. En effet, la valeur des String est définitive, à chaque fois que tu fais un += cela recréé un nouveau String (c'est à dire un nouveau tableau de caractères) et c'est extrêmement coûteux, surtout quand tu le fais pour chaque octet (c'est à dire plusieurs millions de fois dans ton programme !)

L'idéal est de laisser PrintWriter gérer tout seul l'ajout de données, il fait cela très bien !

public static void createRandomFile(String nameFile, int sizeFile) throws IOException
{
    FileWriter fw = new FileWriter(nameFile);
    
    for (int i = 0, n = sizeFile * 1024 * 1024; i < n; i++ )
        fw.append(getRandomChar());
    
    fw.close();
}


6) Dernière remarque pour terminer : le Mo est une unité de la base 10. Comme pour 1 kg ou 1 km, 1 ko fait 1000 octets, et 1 Mo fait 1000*1000 octets. Les unités en base 2 utilisés en informatiques sont le kio et le Mio (kibioctets et mébioctets).
Et même si Windows ne respecte pas ces notations (pour ne pas troubler le grand public), les autres systèmes d'exploitations eux parlent bien de Mio. En tant que développeur il est quand même mieux de faire cette différence.

Note : afin d'être complet, voici les import nécessaires à l'exécution des morceaux de code que je t'ai donné :

import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.Scanner;
La confiance n'exclut pas le contrôle
0
Rejoignez-nous