Программа запускается с одним параметром именем файла который содержит английский текст
В прошлой публикации мы установили и настроили Sublime Text в качестве редактора для написания кода на Java.
- о компиляции и запуске Java-программ из консоли
- как выводить в нее корректно русский текст
- способ отображения байт-кода
На первых порах начинающему программисту очень важно научиться выполнять необходимые действия минимальными средствами, чтобы:
- иметь представление, что происходит «под капотом»
- не быть зависимым от среды разработки
- не превратиться в специалиста по нажиманию кнопок в инструментах для профессионалов
- не оказаться беспомощным за их пределами
Вам сейчас нужно максимально набить шишек, находясь в спартанских условиях, которые закалят и научат самостоятельно и оперативно решать возникающие проблемы. Это придаст уверенности и повысит вашу экспертность.
Есть такое понятие — профессиональный кругозор. Он важен для людей любой профессии. Программисты не исключение. Если человек хочет стать настоящим разработчиком, обладающим фундаментальным знанием, а не поверхностным и неструктурированным, то ему нужно изучать возможности языка последовательно и системно. Компиляция и запуск — это основа основ, это база, мимо которой никак нельзя пройти.
Компилировать и запускать программы, на первых порах, мы будем из консоли. В этой и последующих статьях мы будем много работать с этим инструментом. Это важный навык, который используется программистами повсеместно.
Откроем в Sublime Text терминал, нажав Ctrl + Alt + T (при этом файл MyFirstApp.java должен быть открыт в редакторе). Обязательно проверьте, что терминал запустился в папке StartJava (или где вы сохранили класс).
Для компиляции воспользуемся уже знакомой утилитой javac (java compiler, компилятор java). Она нужна для преобразования Java-кода в язык виртуальной машины (байт-код).
Как мы уже знаем, MyFirstApp.class содержит байт-код. Для его исполнения воспользуемся утилитой java. Именно она стартует JVM, которая в свою очередь запустит класс MyFirstApp.
Обратите внимание, что необходимо указать не имя файла MyFirstApp.class, а имя класса. При этом писать какое-либо расширение не нужно. Утилита java принимает в качестве параметра именно имя класса, а не имя файла, где он находится.
Мы уже не первый раз упоминаем про байт-код, но до сих пор в глаза его не видели. Исправим эту ситуацию.
Для отображения (декомпиляции) байт-кода класса необходимо в консоли написать команду javap -c MyFirstApp.
Как правило, умение читать и понимать байт-код, вносить в него изменения для рядовых Java-разработчиков обычно не требуется — это очень специфические знания. Так что долго не сидите на этой теме.
Если обобщить все этапы, которые проходит программа перед запуском, то схематично их можно отобразить в виде схемы:
Чтобы посмотреть, как работает программа, необходимо выполнить два действия: компиляцию и запуск. Если эти шаги требуется исполнять часто, то данный процесс рано или поздно надоест. Хотелось бы его упростить.
Удалите из папки class-файл, чтобы все было честно. И запустите программу без компиляции в явном виде, написав java MyFirstApp.java.
Мы только что запустили (и скомпилировали) файл с java-кодом без использования команды javac. При этом исходный код в любом случае компилируется в памяти (без создания на диске class-файла), а затем исполняется JVM.
Эта функция ограничена кодом, который хранится в одном файле. Она не сработает для программ, состоящих из двух и более файлов.
Теперь, когда вы умеете компилировать и запускать программу, можете поэкспериментировать с кодом MyFirstApp.java, внося в него изменения. Попробуем удалить точку с запятой.
Если вы используете Linux или macOS, то дальше можете не читать, т.к. ниже описаны проблемы и их решения для Windows. У вас таких проблем не будет!
Написанная нами программа выводит текст в консоли на английском языке. Как вы думаете, что произойдет, если попробовать вывести текст на русском?
Первое, что приходит в голову — это какая-то проблема с кодировкой. Нужно разобраться в какой момент она возникает.
Посмотрим, какая кодировка у файла с нашим кодом. Она отображается в правом нижнем углу окна. Видим, что это UTF-8.
А какая кодировка используется в OC? Определить это можно разными путями. Например, в Windows в реестре (для его запуска из консоли используйте команду regedit) по следующему адресу HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage можно посмотреть, чему равен параметр под названием ACP (ANSI code page).
У меня он имеет значение 1251. Это стандартная кодировка для русских версий Windows. У вас она может быть другой — все зависит от языка (кодировки) системы.
Есть еще один способ узнать кодировку, который подходит для любой ОС — это воспользоваться Java, поместив в наш класс две новых строки:
Вникать в то, что означает этот код мы не будем — наша задача лишь получить универсальным способом значение кодировки. Но, если в двух словах, то в первой строке мы подключаем класс Charset, а в пятой выводим на экран значение кодировки по умолчанию для ОС, воспользовавшись возможностями данного класса.
Она выдала 866. Это же число можно наблюдать и в реестре у параметра OEMCP (Original equipment manufacturer code page). Это DOS-кодировка, которая досталась нам в наследство.
Не удивительно, что java не смогла корректно отобразить кириллический текст, когда используется столько кодировок в одной ОС.
Дело в том, что во время компиляции компилятор определяет кодировку исходного кода, опираясь на значение кодировки по умолчанию (на кодировку вашей ОС), а не на кодировку файла. В разных системах используются разные кодировки по умолчанию: в Windows — windows-1251, в Linux и Mac — UTF-8.
В Windows ко всему прочему еще и кодировка консоли не совпадает с кодировкой системы! Консоль по историческим причинам имеет кодировку Cp866 (видимо, в целях совместимости).
Затем JVM определяет кодировку по умолчанию во время запуска, используя системное свойство file.encoding. Значение для этого свойства устанавливается Java-машиной один раз при старте на основании данных, взятых из ОС.
Кодировка, используемая при выводе в консоль тоже системная, а не консоли. Если они не совпадают, то не видать нам корректного вывода кириллицы.
В итоге кодировку надо учитывать во время компиляции, во время запуска и во время вывода текста на консоль, например, при вводе с клавиатуры. Невыполнение этого правила в любом из этих мест способно вызвать проблемы.
У компилятора есть опция -encoding. Она позволяет принудительно указать кодировку исходника, чтобы компилятор не определял ее, опираясь на кодировку системы. Как вы помните, файл имеет кодировку UTF-8. Вот ее мы и укажем javac -encoding utf8 MyFirstApp. java.
Если для однофайловых программы вы решили не использовать явно компиляцию, а сразу писать java, то для переопределения системного свойства file.encoding существует специальная команда. Вместе с ней запуск программы будет выглядеть так java -Dfile.encoding=UTF8 MyFirstApp.java.
-Dfile.encoding — это уже параметр JVM, с помощью которого мы устанавливаем принудительно нужное нам значение, сохраняя его в file.encoding.
От всех этих параметров и правил может закружиться голова. И все эти годы Java-разработчики жили и мучились с кодировками и ошибками, которые они вызывали в программах.
Но, не прошло и 25 лет, как появилась хорошая новость. Начиная с Java 18, значение кодировки по умолчанию определяется не исходя из кодировки ОС, а исходя из того, что она является UTF-8 — отныне это кодировка по умолчанию. Никакие параметры больше не нужны. Убедимся в этом:
Для тех, кто использует Java меньше 18, придется использовать все параметры, указанные ранее — ни куда от них не деться. Но и тут есть выход.
Утомительно все время указывать кодировку. Этот вопрос можно решить, используя JAVA_TOOL_OPTIONS со значением -Dfile.encoding=UTF8. Необходимо установить эту переменную и ее значение в качестве переменной среды (ранее мы уже имели дело с другой переменной — JAVA_HOME).
Забежим немного вперед и рассмотрим ситуацию, когда нам нужно ввести с клавиатуры что-то на русском языке. Да, ввод мы еще не проходили, но мне совсем не хочется размазывать эту информацию по разным статьям. Пусть все, что связано с компиляцией и запуском, с кодировками, их проблемы и решения будут в одном месте.
Добавим в наш код библиотечный класс Scanner, который позволит считывать, введенные с клавиатуры символы , и пару строк с его использованием:
Чтобы решить проблему, замените строку Scanner console = new Scanner(System.in); на Scanner console = new Scanner(System.in, «cp866»); Тут мы явно указываем кодировку cp866 — это кодировка консоли, как вы помните.
Если после всего проделанного, что я описал выше, у вас вместо русского текста выводится пустая строка, то необходимо в консоли ввести chcp 866 и заново запустить программу.
В этой статье мы научились компилировать и запускать java-программы, нашли способ побороть проблему с выводом кириллических символов в консоль, а также лучше стали понимать, как работают все эти механизмы.
Если не использовать в коде программы или во время ввода с клавиатуры русский язык, то никаких проблем с кодировками не возникнет. Но, если вы все же ступили на путь использования кириллических символов, то вам придется проделать все те настройки, которые были описаны во второй половине статьи. Таких проблем в профессиональных средах разработки практически не бывает, т.к. они умеют правильно отображать текст в консоли, делая автоматически, если нужно, его перекодировку.
Решение задачи task1821 - Встречаемость символов. Программа запускается с одним параметром — именем файла, который содержит английский текст. Посчитать частоту встречания каждого символа. Отсортировать результат по возрастанию кода ASCII.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com . javarush . task . task18 . task1821 ; |
/* |
Встречаемость символов |
*/ |
import java . io . FileInputStream ; |
import java . util . Map ; |
import java . util . TreeMap ; |
public class Solution |
public static void main ( String [] args ) throws Exception |
String file = args [ 0 ]; |
FileInputStream fis = new FileInputStream ( file ); |
TreeMap < Character , Integer >map = new TreeMap <>(); |
while ( fis . available () > 0 ) |
char a = ( char ) fis . read (); |
if (! map . containsKey ( a )) |
map . put ( a , 1 ); |
> else map . put ( a , map . get ( a )+ 1 ); |
> |
for ( Map . Entry < Character , Integer >item : map . entrySet ()) |
System . out . println ( item . getKey () + " " + item . getValue ()); |
> |
fis . close (); |
> |
> |
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com . javarush . test . level18 . lesson10 . home06 ; |
/* Встречаемость символов |
Программа запускается с одним параметром - именем файла, который содержит английский текст. |
Посчитать частоту встречания каждого символа. |
Отсортировать результат по возрастанию кода ASCII (почитать в инете). Пример: ','=44, 's'=115, 't'=116 |
Вывести на консоль отсортированный результат: |
[символ1] частота1 |
[символ2] частота2 |
Закрыть потоки |
Пример вывода: |
, 19 |
- 7 |
f 361 |
*/ |
import java . io .*; |
import java . util . Arrays ; |
import java . util . HashMap ; |
public class Solution |
public static void main ( String [] args ) throws IOException |
FileInputStream inputStream = new FileInputStream ( new File ( args [ 0 ])); |
// BufferedReader rd = new BufferedReader(new InputStreamReader(System.in)); |
// FileInputStream inputStream = new FileInputStream(new File(rd.readLine())); |
byte [] symbols = new byte [ inputStream . available ()]; |
inputStream . read ( symbols ); |
Arrays . sort ( symbols ); |
HashMap < Byte , Integer >map = new HashMap < Byte , Integer >(); |
int count ; |
for ( byte x : symbols ) |
count = 0 ; |
for ( byte x1 : symbols ) |
if ( x == x1 ) |
count ++; |
> |
> |
if (! map . containsKey ( x )) |
map . put ( x , count ); |
System . out . println (( char ) x + " " + count ); |
> |
> |
inputStream . close (); |
> |
> |
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Как передать имена входных файлов
Как передать имена входных файлов при запуске( через параметры main())
Имена входных и выходных файлов задаются через аргументы командной строки
Как программе передать аргументы через командную строку? Приложение консольное. Насколько я.
Решение
Al_Kaz, параметр argc - целое число, хранящее количество аргументов командной строки.. минимально равен единице, т.к. имя программы является первым аргументом.. параметр argv - указатель на массив указателей других аргументов.. все аргументы командной строки являются строками..
Al_Kaz, пользователю ничего не нужно связывать, данный процесс происходит автоматически..
просто файлы должны лежать в той же папке, что и сама программа..
или указывать полный путь к файлам в передаваемых аргументах..
Простите меня, я совершенно не могу понять как это сделать.
Программа не работает, если вызывать файлы через параметры main
Добавлено через 26 минут
Разобралась! Спасибо Вам
TreeView: при запуске программы все родительские элементы должны быть открыты
Ребята, подскажите какое свойство в TreeView отвечает за это: Нужно что бы при запуске программы.
Имена формальных и фактических параметров должны отличаться?
Здравствуйте. В институте преподаватель сказала, что "Имена фактических и формальных параметров не.
Ошибка сегментирования при запуске программе
После запуска команды ./runme выходит ошибка сегментирования (после ввода make ошибок не было). Я.
Ошибка в программе при запуске на Windows xp
for i:='A' to 'Z' do //Если флеш-диск нашелся, то. if (GetDriveType(PChar(i+':\')) =.
- Привет, Амиго! Сегодня мы будет знакомиться с потоками ввода-вывода . Пару дней назад мы немного цепляли данную тему, но сегодня пройдемся по ней основательно. Потоки ввода-вывода делятся на 4 категории:
1) Потоки делятся по направлению: потоки ввода и потоки вывода
2) Потоки делятся по типу данных: работают с байтами или работают с символами.
Поток ввода | Поток вывода | |
---|---|---|
Работает с байтами | InputStream | OutputStream |
Работает с символами | Reader | Writer |
Если объект реализует интерфейс InputStream, значит, он поддерживает последовательное чтение из него байт (byte).
Если объект реализует интерфейс OutputStream, значит, он поддерживает последовательную запись в него байт (byte).
Если объект реализует интерфейс Reader, значит, он поддерживает последовательное чтение из него символов (char).
Если объект реализует интерфейс Writer, значит, он поддерживает последовательную запись в него символов (char).
Поток вывода напоминает принтер. На принтер мы можем выводить документы. В поток вывода мы можем выводить данные.
Тогда поток ввода можно сравнить со сканером, ну или с розеткой. С помощью сканера мы можем ввести документы к себе в компьютер. Также мы можем подключится к розетке и получать из нее электричество. Из потока ввода мы можем получать данные.
- А где они используются?
- Эти классы используются в Java повсеместно. Известный нам System.in – это статическая переменная по имени in типа InputStream в классе System.
- Надо же! Оказывается, все это время я пользовался потоком InputStream и не знал об этом. System.out – тоже поток?
- Да, System.out – это статическая переменная по имени out типа PrintStream (наследник OutputStream) в классе System.
- Т.е. я все время пользовался потоками и даже не подозревал об этом?
- Да, и это говорит лишь о том, насколько такие потоки удобны. Просто берешь и пользуешься.
- Хотя этого нельзя сказать про System.in. К нему постоянно приходилось добавлять BufferedReader и InputStreamReader.
- Да, это так. Но на это тоже были свои причины.
Видишь ли, типов данных очень много, как и способов работы с ними. Поэтому количество стандартных классов ввода-вывода очень быстро росло, хоть они и делали все почти то же самое. Чтобы избежать такой сложности, разработчики Java применили принцип абстракции и разделили классы на много маленьких частей.
Зато их можно соединить последовательно и получить очень сложную функциональность, если она тебе понадобилась. Смотри пример:
Вывод строки на консоль |
System.out.println("Hello"); |
Сохранили поток вывода на консоль в отдельную переменную. Выводим в поток строку. |
PrintStream console = System.out; console.println("Hello"); |
Создали динамический (растягивающийся) массив байт в памяти. Связали его с новым потоком вывода – объектов PrintStream Выводим в поток строку. |
ByteArrayOutputStream stream = new ByteArrayOutputStream(); PrintStream console = new PrintStream(stream); console.println("Hello"); |
- Действительно, чем-то похоже на конструктор Lego. Только непонятно, что весь этот код делает.
- Пусть это тебя не беспокоит сейчас. Всему свое время.
Хочу, чтобы ты запомнил вот что: если класс реализует интерфейс OutputStream – он позволяет записывать в него байты. Почти так же, как ты выводишь данные на консоль. Что он будет с этими данными делать – его задача. В «конструкторе» важно не назначение отдельного элемента, а насколько классные вещи мы можем собрать, благодаря многообразию существующих элементов.
- Хорошо. Тогда с чего мы начнем?
2. FileInputStream, FileOutputStream
- А начнем мы с потоков для ввода/вывода файлов. Но обо всем по порядку.
Для чтений и записи файлов есть два класса: FileInputStream и FileOutputStream . Как ты уже, наверное, догадался, FileInputStream позволяет последовательно читать из файла байты, а FileOutputStream – записывать в файл байты. Вот какие методы есть у этих классов:
Метод | Что метод делает |
---|---|
FileInputStream (String fileName); | - это конструктор. Позволяет указать имя файла на диске, из которого созданный объект будет читать данные. |
int read (); | - метод читает один байт из файла и возвращает его как результат. Тип результата расширяется до int. |
int available (); | - метод возвращает количество непрочитанных (доступных) байт. |
void close (); | - метод «закрывает» поток, вызывается после окончания работы с потоком. Объект выполняет служебные операции, связанные с закрытием файла на диске и т.д. Из потока больше нельзя читать данные. |
Давай ради интереса посчитаем сумму всех байт в файле на диске. Вот как будет выглядеть этот код:
while ( inputStream . available () > 0) //пока остались непрочитанные байты
int data = inputStream . read (); //прочитать очередной байт
sum += data ; //добавить его к общей сумме
>
inputStream . close (); // закрываем поток
- Мы уже раньше что-то подобное разбирали. А как устроен FileOutputStream?
- Да, тут фактически только один метод для записи – write, который записывает только один байт за раз. Но благодаря ему можно записать в файл сколько угодно информации.
Программирование – это процесс разбиения одной большой и сложной задачи на много маленьких. Тут происходит практически тот же процесс: чтение и запись больших данных маленькими порциями – по кусочкам – по одному байту.
Вот как можно скопировать файл на диске, пользуясь этими классами:
while ( inputStream.available() > 0) //пока есть еще непрочитанные байты
int data = inputStream . read(); // прочитать очередной байт в переменную data
outputStream . write (data); // и записать его во второй поток
>
Читайте также: